diff --git a/.prettierrc.json b/.prettierrc.json index 1531ce9e..9a629901 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,11 +1,24 @@ { - "printWidth": 150, + "printWidth": 90, "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": false, - "quoteProps": "preserve", "trailingComma": "none", "bracketSpacing": true, - "arrowParens": "avoid" + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.tsx", + "options": { + "printWidth": 150 + } + }, + { + "files": "useUserProfileForm.tsx", + "options": { + "printWidth": 150 + } + } + ] } diff --git a/package.json b/package.json index 13d840b8..5bb7b502 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "make-fetch-happen": "^11.0.3", "patch-package": "^8.0.0", "powerhooks": "^1.0.10", - "prettier": "^2.3.0", + "prettier": "^3.2.5", "properties-parser": "^0.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/scripts/build.ts b/scripts/build.ts index c327cd5f..56b7b844 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -10,7 +10,10 @@ console.log(chalk.cyan("Building Keycloakify...")); const startTime = Date.now(); if (fs.existsSync(join("dist", "bin", "main.original.js"))) { - fs.renameSync(join("dist", "bin", "main.original.js"), join("dist", "bin", "main.js")); + fs.renameSync( + join("dist", "bin", "main.original.js"), + join("dist", "bin", "main.js") + ); fs.readdirSync(join("dist", "bin")).forEach(fileBasename => { if (/[0-9]\.index.js/.test(fileBasename)) { @@ -28,55 +31,74 @@ if (!fs.readFileSync(join("dist", "bin", "main.js")).toString("utf8").includes(" run(`npx ncc build ${join("dist", "bin", "main.js")} -o ${join("dist", "ncc_out")}`); transformCodebase({ - "srcDirPath": join("dist", "ncc_out"), - "destDirPath": join("dist", "bin"), - "transformSourceCode": ({ fileRelativePath, sourceCode }) => { + srcDirPath: join("dist", "ncc_out"), + destDirPath: join("dist", "bin"), + transformSourceCode: ({ fileRelativePath, sourceCode }) => { if (fileRelativePath === "index.js") { return { - "newFileName": "main.js", - "modifiedSourceCode": sourceCode + newFileName: "main.js", + modifiedSourceCode: sourceCode }; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); -fs.rmSync(join("dist", "ncc_out"), { "recursive": true }); +fs.rmSync(join("dist", "ncc_out"), { recursive: true }); patchDeprecatedBufferApiUsage(join("dist", "bin", "main.js")); fs.chmodSync( join("dist", "bin", "main.js"), - fs.statSync(join("dist", "bin", "main.js")).mode | fs.constants.S_IXUSR | fs.constants.S_IXGRP | fs.constants.S_IXOTH + fs.statSync(join("dist", "bin", "main.js")).mode | + fs.constants.S_IXUSR | + fs.constants.S_IXGRP | + fs.constants.S_IXOTH ); run(`npx tsc -p ${join("src", "tsconfig.json")}`); run(`npx tsc-alias -p ${join("src", "tsconfig.json")}`); if (fs.existsSync(join("dist", "vite-plugin", "index.original.js"))) { - fs.renameSync(join("dist", "vite-plugin", "index.original.js"), join("dist", "vite-plugin", "index.js")); + fs.renameSync( + join("dist", "vite-plugin", "index.original.js"), + join("dist", "vite-plugin", "index.js") + ); } run(`npx tsc -p ${join("src", "vite-plugin", "tsconfig.json")}`); -if (!fs.readFileSync(join("dist", "vite-plugin", "index.js")).toString("utf8").includes("ncc")) { - fs.cpSync(join("dist", "vite-plugin", "index.js"), join("dist", "vite-plugin", "index.original.js")); +if ( + !fs + .readFileSync(join("dist", "vite-plugin", "index.js")) + .toString("utf8") + .includes("ncc") +) { + fs.cpSync( + join("dist", "vite-plugin", "index.js"), + join("dist", "vite-plugin", "index.original.js") + ); } -run(`npx ncc build ${join("dist", "vite-plugin", "index.js")} -o ${join("dist", "ncc_out")}`); +run( + `npx ncc build ${join("dist", "vite-plugin", "index.js")} -o ${join( + "dist", + "ncc_out" + )}` +); transformCodebase({ - "srcDirPath": join("dist", "ncc_out"), - "destDirPath": join("dist", "vite-plugin"), - "transformSourceCode": ({ fileRelativePath, sourceCode }) => { + srcDirPath: join("dist", "ncc_out"), + destDirPath: join("dist", "vite-plugin"), + transformSourceCode: ({ fileRelativePath, sourceCode }) => { assert(fileRelativePath === "index.js"); - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); -fs.rmSync(join("dist", "ncc_out"), { "recursive": true }); +fs.rmSync(join("dist", "ncc_out"), { recursive: true }); patchDeprecatedBufferApiUsage(join("dist", "vite-plugin", "index.js")); @@ -85,7 +107,7 @@ console.log(chalk.green(`✓ built in ${((Date.now() - startTime) / 1000).toFixe function run(command: string) { console.log(chalk.grey(`$ ${command}`)); - child_process.execSync(command, { "stdio": "inherit" }); + child_process.execSync(command, { stdio: "inherit" }); } function patchDeprecatedBufferApiUsage(filePath: string) { diff --git a/scripts/dump-keycloak-realm.ts b/scripts/dump-keycloak-realm.ts index 05b306bb..c50269c9 100644 --- a/scripts/dump-keycloak-realm.ts +++ b/scripts/dump-keycloak-realm.ts @@ -4,15 +4,34 @@ import { SemVer } from "../src/bin/tools/SemVer"; import { join as pathJoin, relative as pathRelative } from "path"; import chalk from "chalk"; -run([`docker exec -it ${containerName}`, `/opt/keycloak/bin/kc.sh export`, `--dir /tmp`, `--realm myrealm`, `--users realm_file`].join(" ")); +run( + [ + `docker exec -it ${containerName}`, + `/opt/keycloak/bin/kc.sh export`, + `--dir /tmp`, + `--realm myrealm`, + `--users realm_file` + ].join(" ") +); const keycloakMajorVersionNumber = SemVer.parse( - child_process.execSync(`docker inspect --format '{{.Config.Image}}' ${containerName}`).toString("utf8").trim().split(":")[1] + child_process + .execSync(`docker inspect --format '{{.Config.Image}}' ${containerName}`) + .toString("utf8") + .trim() + .split(":")[1] ).major; const targetFilePath = pathRelative( process.cwd(), - pathJoin(__dirname, "..", "src", "bin", "start-keycloak", `myrealm-realm-${keycloakMajorVersionNumber}.json`) + pathJoin( + __dirname, + "..", + "src", + "bin", + "start-keycloak", + `myrealm-realm-${keycloakMajorVersionNumber}.json` + ) ); run(`docker cp ${containerName}:/tmp/myrealm-realm.json ${targetFilePath}`); @@ -22,5 +41,5 @@ console.log(`${chalk.green(`✓ Exported realm to`)} ${chalk.bold(targetFilePath function run(command: string) { console.log(chalk.grey(`$ ${command}`)); - return child_process.execSync(command, { "stdio": "inherit" }); + return child_process.execSync(command, { stdio: "inherit" }); } diff --git a/scripts/generate-i18n-messages.ts b/scripts/generate-i18n-messages.ts index a01613e7..89bb590e 100644 --- a/scripts/generate-i18n-messages.ts +++ b/scripts/generate-i18n-messages.ts @@ -1,6 +1,11 @@ import "minimal-polyfills/Object.fromEntries"; import * as fs from "fs"; -import { join as pathJoin, relative as pathRelative, dirname as pathDirname, sep as pathSep } from "path"; +import { + join as pathJoin, + relative as pathRelative, + dirname as pathDirname, + sep as pathSep +} from "path"; import { crawl } from "../src/bin/tools/crawl"; import { downloadKeycloakDefaultTheme } from "../src/bin/shared/downloadKeycloakDefaultTheme"; import { getThisCodebaseRootDirPath } from "../src/bin/tools/getThisCodebaseRootDirPath"; @@ -19,18 +24,26 @@ async function main() { const tmpDirPath = pathJoin(thisCodebaseRootDirPath, "tmp_xImOef9dOd44"); - rmSync(tmpDirPath, { "recursive": true, "force": true }); + rmSync(tmpDirPath, { recursive: true, force: true }); fs.mkdirSync(tmpDirPath); - fs.writeFileSync(pathJoin(tmpDirPath, ".gitignore"), Buffer.from("/*\n!.gitignore\n", "utf8")); + fs.writeFileSync( + pathJoin(tmpDirPath, ".gitignore"), + Buffer.from("/*\n!.gitignore\n", "utf8") + ); await downloadKeycloakDefaultTheme({ keycloakVersion, - "destDirPath": tmpDirPath, - "buildOptions": { - "cacheDirPath": pathJoin(thisCodebaseRootDirPath, "node_modules", ".cache", "keycloakify"), - "npmWorkspaceRootDirPath": thisCodebaseRootDirPath + destDirPath: tmpDirPath, + buildOptions: { + cacheDirPath: pathJoin( + thisCodebaseRootDirPath, + "node_modules", + ".cache", + "keycloakify" + ), + npmWorkspaceRootDirPath: thisCodebaseRootDirPath } }); @@ -40,11 +53,13 @@ async function main() { { const baseThemeDirPath = pathJoin(tmpDirPath, "base"); - const re = new RegExp(`^([^\\${pathSep}]+)\\${pathSep}messages\\${pathSep}messages_([^.]+).properties$`); + const re = new RegExp( + `^([^\\${pathSep}]+)\\${pathSep}messages\\${pathSep}messages_([^.]+).properties$` + ); crawl({ - "dirPath": baseThemeDirPath, - "returnedPathsType": "relative to dirPath" + dirPath: baseThemeDirPath, + returnedPathsType: "relative to dirPath" }).forEach(filePath => { const match = filePath.match(re); @@ -55,14 +70,21 @@ async function main() { const [, typeOfPage, language] = match; (record[typeOfPage] ??= {})[language.replace(/_/g, "-")] = Object.fromEntries( - Object.entries(propertiesParser.parse(fs.readFileSync(pathJoin(baseThemeDirPath, filePath)).toString("utf8"))).map( - ([key, value]: any) => [key === "locale_pt_BR" ? "locale_pt-BR" : key, value.replace(/''/g, "'")] - ) + Object.entries( + propertiesParser.parse( + fs + .readFileSync(pathJoin(baseThemeDirPath, filePath)) + .toString("utf8") + ) + ).map(([key, value]: any) => [ + key === "locale_pt_BR" ? "locale_pt-BR" : key, + value.replace(/''/g, "'") + ]) ); }); } - rmSync(tmpDirPath, { "recursive": true }); + rmSync(tmpDirPath, { recursive: true }); Object.keys(record).forEach(themeType => { const recordForPageType = record[themeType]; @@ -71,19 +93,28 @@ async function main() { return; } - const baseMessagesDirPath = pathJoin(thisCodebaseRootDirPath, "src", themeType, "i18n", "baseMessages"); + const baseMessagesDirPath = pathJoin( + thisCodebaseRootDirPath, + "src", + themeType, + "i18n", + "baseMessages" + ); const languages = Object.keys(recordForPageType); const generatedFileHeader = [ - `//This code was automatically generated by running ${pathRelative(thisCodebaseRootDirPath, __filename)}`, + `//This code was automatically generated by running ${pathRelative( + thisCodebaseRootDirPath, + __filename + )}`, "//PLEASE DO NOT EDIT MANUALLY" ].join("\n"); languages.forEach(language => { const filePath = pathJoin(baseMessagesDirPath, `${language}.ts`); - fs.mkdirSync(pathDirname(filePath), { "recursive": true }); + fs.mkdirSync(pathDirname(filePath), { recursive: true }); fs.writeFileSync( filePath, @@ -92,7 +123,11 @@ async function main() { generatedFileHeader, "", "/* spell-checker: disable */", - `const messages= ${JSON.stringify(recordForPageType[language], null, 2)};`, + `const messages= ${JSON.stringify( + recordForPageType[language], + null, + 2 + )};`, "", "export default messages;", "/* spell-checker: enable */" @@ -117,7 +152,10 @@ async function main() { ` case "en": return en;`, ...languages .filter(language => language !== "en") - .map(language => ` case "${language}": return import("./${language}");`), + .map( + language => + ` case "${language}": return import("./${language}");` + ), ' default: return { "default": {} };', " }", " })();", diff --git a/scripts/grant-exec-perms.ts b/scripts/grant-exec-perms.ts index 10d44bb4..871eae65 100644 --- a/scripts/grant-exec-perms.ts +++ b/scripts/grant-exec-perms.ts @@ -10,7 +10,8 @@ import { chmod, stat } from "fs/promises"; const promises = Object.values(bin).map(async scriptPath => { const fullPath = pathJoin(thisCodebaseRootDirPath, scriptPath); const oldMode = (await stat(fullPath)).mode; - const newMode = oldMode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH; + const newMode = + oldMode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH; await chmod(fullPath, newMode); }); diff --git a/scripts/link-in-app.ts b/scripts/link-in-app.ts index 8314ba3c..a8df9afb 100644 --- a/scripts/link-in-app.ts +++ b/scripts/link-in-app.ts @@ -13,20 +13,26 @@ fs.writeFileSync( Buffer.from( JSON.stringify( (() => { - const packageJsonParsed = JSON.parse(fs.readFileSync(pathJoin(rootDirPath, "package.json")).toString("utf8")); + const packageJsonParsed = JSON.parse( + fs + .readFileSync(pathJoin(rootDirPath, "package.json")) + .toString("utf8") + ); return { ...packageJsonParsed, - "main": packageJsonParsed["main"]?.replace(/^dist\//, ""), - "types": packageJsonParsed["types"]?.replace(/^dist\//, ""), - "module": packageJsonParsed["module"]?.replace(/^dist\//, ""), - "exports": !("exports" in packageJsonParsed) + main: packageJsonParsed["main"]?.replace(/^dist\//, ""), + types: packageJsonParsed["types"]?.replace(/^dist\//, ""), + module: packageJsonParsed["module"]?.replace(/^dist\//, ""), + exports: !("exports" in packageJsonParsed) ? undefined : Object.fromEntries( - Object.entries(packageJsonParsed["exports"]).map(([key, value]) => [ - key, - (value as string).replace(/^\.\/dist\//, "./") - ]) + Object.entries(packageJsonParsed["exports"]).map( + ([key, value]) => [ + key, + (value as string).replace(/^\.\/dist\//, "./") + ] + ) ) }; })(), @@ -39,9 +45,9 @@ fs.writeFileSync( const destSrcDirPath = pathJoin(rootDirPath, "dist", "src"); -fs.rmSync(destSrcDirPath, { "recursive": true, "force": true }); +fs.rmSync(destSrcDirPath, { recursive: true, force: true }); -fs.cpSync(pathJoin(rootDirPath, "src"), destSrcDirPath, { "recursive": true }); +fs.cpSync(pathJoin(rootDirPath, "src"), destSrcDirPath, { recursive: true }); const commonThirdPartyDeps = (() => { // For example [ "@emotion" ] it's more convenient than @@ -53,7 +59,9 @@ const commonThirdPartyDeps = (() => { ...namespaceSingletonDependencies .map(namespaceModuleName => fs - .readdirSync(pathJoin(rootDirPath, "node_modules", namespaceModuleName)) + .readdirSync( + pathJoin(rootDirPath, "node_modules", namespaceModuleName) + ) .map(submoduleName => `${namespaceModuleName}/${submoduleName}`) ) .reduce((prev, curr) => [...prev, ...curr], []), @@ -63,21 +71,25 @@ const commonThirdPartyDeps = (() => { const yarnGlobalDirPath = pathJoin(rootDirPath, ".yarn_home"); -fs.rmSync(yarnGlobalDirPath, { "recursive": true, "force": true }); +fs.rmSync(yarnGlobalDirPath, { recursive: true, force: true }); fs.mkdirSync(yarnGlobalDirPath); const execYarnLink = (params: { targetModuleName?: string; cwd: string }) => { const { targetModuleName, cwd } = params; - const cmd = ["yarn", "link", ...(targetModuleName !== undefined ? [targetModuleName] : ["--no-bin-links"])].join(" "); + const cmd = [ + "yarn", + "link", + ...(targetModuleName !== undefined ? [targetModuleName] : ["--no-bin-links"]) + ].join(" "); console.log(`$ cd ${pathRelative(rootDirPath, cwd) || "."} && ${cmd}`); execSync(cmd, { cwd, - "env": { + env: { ...process.env, - "HOME": yarnGlobalDirPath + HOME: yarnGlobalDirPath } }); }; @@ -93,7 +105,9 @@ const testAppPaths = (() => { return testAppPath; } - console.warn(`Skipping ${testAppName} since it cant be found here: ${testAppPath}`); + console.warn( + `Skipping ${testAppName} since it cant be found here: ${testAppPath}` + ); return undefined; }) @@ -105,7 +119,7 @@ if (testAppPaths.length === 0) { process.exit(-1); } -testAppPaths.forEach(testAppPath => execSync("yarn install", { "cwd": testAppPath })); +testAppPaths.forEach(testAppPath => execSync("yarn install", { cwd: testAppPath })); console.log("=== Linking common dependencies ==="); @@ -118,29 +132,37 @@ commonThirdPartyDeps.forEach(commonThirdPartyDep => { console.log(`${current}/${total} ${commonThirdPartyDep}`); const localInstallPath = pathJoin( - ...[rootDirPath, "node_modules", ...(commonThirdPartyDep.startsWith("@") ? commonThirdPartyDep.split("/") : [commonThirdPartyDep])] + ...[ + rootDirPath, + "node_modules", + ...(commonThirdPartyDep.startsWith("@") + ? commonThirdPartyDep.split("/") + : [commonThirdPartyDep]) + ] ); - execYarnLink({ "cwd": localInstallPath }); + execYarnLink({ cwd: localInstallPath }); }); commonThirdPartyDeps.forEach(commonThirdPartyDep => testAppPaths.forEach(testAppPath => execYarnLink({ - "cwd": testAppPath, - "targetModuleName": commonThirdPartyDep + cwd: testAppPath, + targetModuleName: commonThirdPartyDep }) ) ); console.log("=== Linking in house dependencies ==="); -execYarnLink({ "cwd": pathJoin(rootDirPath, "dist") }); +execYarnLink({ cwd: pathJoin(rootDirPath, "dist") }); testAppPaths.forEach(testAppPath => execYarnLink({ - "cwd": testAppPath, - "targetModuleName": JSON.parse(fs.readFileSync(pathJoin(rootDirPath, "package.json")).toString("utf8"))["name"] + cwd: testAppPath, + targetModuleName: JSON.parse( + fs.readFileSync(pathJoin(rootDirPath, "package.json")).toString("utf8") + )["name"] }) ); diff --git a/scripts/link-in-starter.ts b/scripts/link-in-starter.ts index 0d406eee..05d29ede 100644 --- a/scripts/link-in-starter.ts +++ b/scripts/link-in-starter.ts @@ -2,16 +2,19 @@ import * as child_process from "child_process"; import * as fs from "fs"; import { join } from "path"; -fs.rmSync("node_modules", { "recursive": true, "force": true }); -fs.rmSync("dist", { "recursive": true, "force": true }); -fs.rmSync(".yarn_home", { "recursive": true, "force": true }); +fs.rmSync("node_modules", { recursive: true, force: true }); +fs.rmSync("dist", { recursive: true, force: true }); +fs.rmSync(".yarn_home", { recursive: true, force: true }); run("yarn install"); run("yarn build"); -fs.rmSync(join("..", "keycloakify-starter", "node_modules"), { "recursive": true, "force": true }); +fs.rmSync(join("..", "keycloakify-starter", "node_modules"), { + recursive: true, + force: true +}); -run("yarn install", { "cwd": join("..", "keycloakify-starter") }); +run("yarn install", { cwd: join("..", "keycloakify-starter") }); run(`npx ts-node --skipProject ${join("scripts", "link-in-app.ts")} keycloakify-starter`); @@ -20,5 +23,5 @@ run(`npx chokidar '${join("src", "**", "*")}' -c 'yarn build'`); function run(command: string, options?: { cwd: string }) { console.log(`$ ${command}`); - child_process.execSync(command, { "stdio": "inherit", ...options }); + child_process.execSync(command, { stdio: "inherit", ...options }); } diff --git a/src/PUBLIC_URL.ts b/src/PUBLIC_URL.ts index a1d87dd0..050fb499 100644 --- a/src/PUBLIC_URL.ts +++ b/src/PUBLIC_URL.ts @@ -1,4 +1,7 @@ -import { nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "keycloakify/bin/shared/constants"; +import { + nameOfTheGlobal, + basenameOfTheKeycloakifyResourcesDir +} from "keycloakify/bin/shared/constants"; import { assert } from "tsafe/assert"; /** diff --git a/src/account/Template.tsx b/src/account/Template.tsx index 0d0560c9..b6edc233 100644 --- a/src/account/Template.tsx +++ b/src/account/Template.tsx @@ -24,13 +24,13 @@ export default function Template(props: TemplateProps) { }, []); useSetClassName({ - "qualifiedName": "html", - "className": getClassName("kcHtmlClass") + qualifiedName: "html", + className: getClassName("kcHtmlClass") }); useSetClassName({ - "qualifiedName": "body", - "className": clsx("admin-console", "user", getClassName("kcBodyClass")) + qualifiedName: "body", + className: clsx("admin-console", "user", getClassName("kcBodyClass")) }); useEffect(() => { @@ -46,7 +46,7 @@ export default function Template(props: TemplateProps) { }, []); const { areAllStyleSheetsLoaded } = useInsertLinkTags({ - "hrefs": !doUseDefaultCss + hrefs: !doUseDefaultCss ? [] : [ `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`, diff --git a/src/account/TemplateProps.ts b/src/account/TemplateProps.ts index c19f3312..af02f2a4 100644 --- a/src/account/TemplateProps.ts +++ b/src/account/TemplateProps.ts @@ -2,7 +2,10 @@ import type { ReactNode } from "react"; import type { KcContext } from "./kcContext"; import type { I18n } from "./i18n"; -export type TemplateProps = { +export type TemplateProps< + KcContext extends KcContext.Common, + I18nExtended extends I18n +> = { kcContext: KcContext; i18n: I18nExtended; doUseDefaultCss: boolean; diff --git a/src/account/i18n/i18n.tsx b/src/account/i18n/i18n.tsx index cf3fce03..a4d2717c 100644 --- a/src/account/i18n/i18n.tsx +++ b/src/account/i18n/i18n.tsx @@ -91,19 +91,19 @@ export function createUseI18n(extraMessa setI18n({ ...createI18nTranslationFunctions({ - "fallbackMessages": { + fallbackMessages: { ...fallbackMessages, ...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}), ...(extraMessages[fallbackLanguageTag] ?? {}) } as any, - "messages": { + messages: { ...(await getMessages(currentLanguageTag)), ...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}), ...(extraMessages[currentLanguageTag] ?? {}) } as any }), currentLanguageTag, - "getChangeLocalUrl": newLanguageTag => { + getChangeLocalUrl: newLanguageTag => { const { locale } = kcContext; assert(locale !== undefined, "Internationalization not enabled"); @@ -114,7 +114,7 @@ export function createUseI18n(extraMessa return targetSupportedLocale.url; }, - "labelBySupportedLanguageTag": Object.fromEntries( + labelBySupportedLanguageTag: Object.fromEntries( (kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label]) ) }); @@ -170,7 +170,7 @@ function createI18nTranslationFunctions(params: { })(); return doRenderMarkdown ? ( - + {messageWithArgsInjectedIfAny} ) : ( @@ -186,7 +186,7 @@ function createI18nTranslationFunctions(params: { const keyUnwrappedFromCurlyBraces = match === null ? key : match[1]; const out = resolveMsg({ - "key": keyUnwrappedFromCurlyBraces, + key: keyUnwrappedFromCurlyBraces, args, doRenderMarkdown }); @@ -195,36 +195,46 @@ function createI18nTranslationFunctions(params: { } return { - "msgStr": (key, ...args) => resolveMsg({ key, args, "doRenderMarkdown": false }) as string, - "msg": (key, ...args) => resolveMsg({ key, args, "doRenderMarkdown": true }) as JSX.Element, - "advancedMsg": (key, ...args) => resolveMsgAdvanced({ key, args, "doRenderMarkdown": true }) as JSX.Element, - "advancedMsgStr": (key, ...args) => resolveMsgAdvanced({ key, args, "doRenderMarkdown": false }) as string + msgStr: (key, ...args) => resolveMsg({ key, args, doRenderMarkdown: false }) as string, + msg: (key, ...args) => resolveMsg({ key, args, doRenderMarkdown: true }) as JSX.Element, + advancedMsg: (key, ...args) => + resolveMsgAdvanced({ + key, + args, + doRenderMarkdown: true + }) as JSX.Element, + advancedMsgStr: (key, ...args) => + resolveMsgAdvanced({ + key, + args, + doRenderMarkdown: false + }) as string }; } const keycloakifyExtraMessages = { - "en": { - "shouldBeEqual": "{0} should be equal to {1}", - "shouldBeDifferent": "{0} should be different to {1}", - "shouldMatchPattern": "Pattern should match: `/{0}/`", - "mustBeAnInteger": "Must be an integer", - "notAValidOption": "Not a valid option", - "newPasswordSameAsOld": "New password must be different from the old one", - "passwordConfirmNotMatch": "Password confirmation does not match" + en: { + shouldBeEqual: "{0} should be equal to {1}", + shouldBeDifferent: "{0} should be different to {1}", + shouldMatchPattern: "Pattern should match: `/{0}/`", + mustBeAnInteger: "Must be an integer", + notAValidOption: "Not a valid option", + newPasswordSameAsOld: "New password must be different from the old one", + passwordConfirmNotMatch: "Password confirmation does not match" }, - "fr": { + fr: { /* spell-checker: disable */ - "shouldBeEqual": "{0} doit être égal à {1}", - "shouldBeDifferent": "{0} doit être différent de {1}", - "shouldMatchPattern": "Dois respecter le schéma: `/{0}/`", - "mustBeAnInteger": "Doit être un nombre entier", - "notAValidOption": "N'est pas une option valide", + shouldBeEqual: "{0} doit être égal à {1}", + shouldBeDifferent: "{0} doit être différent de {1}", + shouldMatchPattern: "Dois respecter le schéma: `/{0}/`", + mustBeAnInteger: "Doit être un nombre entier", + notAValidOption: "N'est pas une option valide", - "logoutConfirmTitle": "Déconnexion", - "logoutConfirmHeader": "Êtes-vous sûr(e) de vouloir vous déconnecter ?", - "doLogout": "Se déconnecter", - "newPasswordSameAsOld": "Le nouveau mot de passe doit être différent de l'ancien", - "passwordConfirmNotMatch": "La confirmation du mot de passe ne correspond pas" + logoutConfirmTitle: "Déconnexion", + logoutConfirmHeader: "Êtes-vous sûr(e) de vouloir vous déconnecter ?", + doLogout: "Se déconnecter", + newPasswordSameAsOld: "Le nouveau mot de passe doit être différent de l'ancien", + passwordConfirmNotMatch: "La confirmation du mot de passe ne correspond pas" /* spell-checker: enable */ } }; diff --git a/src/account/kcContext/KcContext.ts b/src/account/kcContext/KcContext.ts index dd38bc63..09242a17 100644 --- a/src/account/kcContext/KcContext.ts +++ b/src/account/kcContext/KcContext.ts @@ -68,7 +68,10 @@ export declare namespace KcContext { * @param text to return * @return text if message exists for given field, else undefined */ - printIfExists: (fieldName: string, text: T) => T | undefined; + printIfExists: ( + fieldName: string, + text: T + ) => T | undefined; /** * Check if exists error message for given fields * diff --git a/src/account/kcContext/createGetKcContext.ts b/src/account/kcContext/createGetKcContext.ts index 93765ba2..f93feab0 100644 --- a/src/account/kcContext/createGetKcContext.ts +++ b/src/account/kcContext/createGetKcContext.ts @@ -4,17 +4,28 @@ import { isStorybook } from "keycloakify/lib/isStorybook"; import type { ExtendKcContext } from "./getKcContextFromWindow"; import { getKcContextFromWindow } from "./getKcContextFromWindow"; import { symToStr } from "tsafe/symToStr"; -import { kcContextMocks, kcContextCommonMock } from "keycloakify/account/kcContext/kcContextMocks"; +import { + kcContextMocks, + kcContextCommonMock +} from "keycloakify/account/kcContext/kcContextMocks"; -export function createGetKcContext(params?: { +export function createGetKcContext< + KcContextExtension extends { pageId: string } = never +>(params?: { mockData?: readonly DeepPartial>[]; mockProperties?: Record; }) { const { mockData, mockProperties } = params ?? {}; - function getKcContext["pageId"] | undefined = undefined>(params?: { + function getKcContext< + PageId extends + | ExtendKcContext["pageId"] + | undefined = undefined + >(params?: { mockPageId?: PageId; - storyPartialKcContext?: DeepPartial, { pageId: PageId }>>; + storyPartialKcContext?: DeepPartial< + Extract, { pageId: PageId }> + >; }): { kcContext: PageId extends undefined ? ExtendKcContext | undefined @@ -32,34 +43,46 @@ export function createGetKcContext pageId === mockPageId); + const kcContextDefaultMock = kcContextMocks.find( + ({ pageId }) => pageId === mockPageId + ); const partialKcContextCustomMock = (() => { const out: DeepPartial> = {}; - const mockDataPick = mockData?.find(({ pageId }) => pageId === mockPageId); + const mockDataPick = mockData?.find( + ({ pageId }) => pageId === mockPageId + ); if (mockDataPick !== undefined) { deepAssign({ - "target": out, - "source": mockDataPick + target: out, + source: mockDataPick }); } if (storyPartialKcContext !== undefined) { deepAssign({ - "target": out, - "source": storyPartialKcContext + target: out, + source: storyPartialKcContext }); } return Object.keys(out).length === 0 ? undefined : out; })(); - if (kcContextDefaultMock === undefined && partialKcContextCustomMock === undefined) { + if ( + kcContextDefaultMock === undefined && + partialKcContextCustomMock === undefined + ) { console.warn( [ `WARNING: You declared the non build in page ${mockPageId} but you didn't `, @@ -72,21 +95,24 @@ export function createGetKcContext(params?: { +export function getKcContext< + KcContextExtension extends { pageId: string } = never +>(params?: { mockPageId?: ExtendKcContext["pageId"]; mockData?: readonly DeepPartial>[]; }): { kcContext: ExtendKcContext | undefined } { diff --git a/src/account/kcContext/getKcContextFromWindow.ts b/src/account/kcContext/getKcContextFromWindow.ts index 84f39340..f29ea9bf 100644 --- a/src/account/kcContext/getKcContextFromWindow.ts +++ b/src/account/kcContext/getKcContextFromWindow.ts @@ -2,10 +2,14 @@ import type { AndByDiscriminatingKey } from "keycloakify/tools/AndByDiscriminati import { nameOfTheGlobal } from "keycloakify/bin/shared/constants"; import type { KcContext } from "./KcContext"; -export type ExtendKcContext = [KcContextExtension] extends [never] +export type ExtendKcContext = [ + KcContextExtension +] extends [never] ? KcContext : AndByDiscriminatingKey<"pageId", KcContextExtension & KcContext.Common, KcContext>; -export function getKcContextFromWindow(): ExtendKcContext | undefined { +export function getKcContextFromWindow< + KcContextExtension extends { pageId: string } = never +>(): ExtendKcContext | undefined { return typeof window === "undefined" ? undefined : (window as any)[nameOfTheGlobal]; } diff --git a/src/account/kcContext/kcContextMocks.ts b/src/account/kcContext/kcContextMocks.ts index 1697cca1..7d66551e 100644 --- a/src/account/kcContext/kcContextMocks.ts +++ b/src/account/kcContext/kcContextMocks.ts @@ -7,254 +7,258 @@ import { BASE_URL } from "keycloakify/lib/BASE_URL"; const resourcesPath = `${BASE_URL}${keycloak_resources}/account/resources`; export const kcContextCommonMock: KcContext.Common = { - "themeVersion": "0.0.0", - "keycloakifyVersion": "0.0.0", - "themeType": "account", - "themeName": "my-theme-name", - "url": { + themeVersion: "0.0.0", + keycloakifyVersion: "0.0.0", + themeType: "account", + themeName: "my-theme-name", + url: { resourcesPath, - "resourcesCommonPath": `${resourcesPath}/${resources_common}`, - "resourceUrl": "#", - "accountUrl": "#", - "applicationsUrl": "#", - "logoutUrl": "#", - "getLogoutUrl": () => "#", - "logUrl": "#", - "passwordUrl": "#", - "sessionsUrl": "#", - "socialUrl": "#", - "totpUrl": "#" + resourcesCommonPath: `${resourcesPath}/${resources_common}`, + resourceUrl: "#", + accountUrl: "#", + applicationsUrl: "#", + logoutUrl: "#", + getLogoutUrl: () => "#", + logUrl: "#", + passwordUrl: "#", + sessionsUrl: "#", + socialUrl: "#", + totpUrl: "#" }, - "realm": { - "internationalizationEnabled": true, - "userManagedAccessAllowed": true + realm: { + internationalizationEnabled: true, + userManagedAccessAllowed: true }, - "messagesPerField": { - "printIfExists": () => { + messagesPerField: { + printIfExists: () => { return undefined; }, - "existsError": () => false, - "get": key => `Fake error for ${key}`, - "exists": () => false + existsError: () => false, + get: key => `Fake error for ${key}`, + exists: () => false }, - "locale": { - "supported": [ + locale: { + supported: [ /* spell-checker: disable */ { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=de", - "label": "Deutsch", - "languageTag": "de" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=de", + label: "Deutsch", + languageTag: "de" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=no", - "label": "Norsk", - "languageTag": "no" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=no", + label: "Norsk", + languageTag: "no" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ru", - "label": "Русский", - "languageTag": "ru" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ru", + label: "Русский", + languageTag: "ru" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sv", - "label": "Svenska", - "languageTag": "sv" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sv", + label: "Svenska", + languageTag: "sv" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR", - "label": "Português (Brasil)", - "languageTag": "pt-BR" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR", + label: "Português (Brasil)", + languageTag: "pt-BR" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt", - "label": "Lietuvių", - "languageTag": "lt" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt", + label: "Lietuvių", + languageTag: "lt" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en", - "label": "English", - "languageTag": "en" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en", + label: "English", + languageTag: "en" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it", - "label": "Italiano", - "languageTag": "it" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it", + label: "Italiano", + languageTag: "it" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr", - "label": "Français", - "languageTag": "fr" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr", + label: "Français", + languageTag: "fr" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN", - "label": "中文简体", - "languageTag": "zh-CN" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN", + label: "中文简体", + languageTag: "zh-CN" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es", - "label": "Español", - "languageTag": "es" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es", + label: "Español", + languageTag: "es" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs", - "label": "Čeština", - "languageTag": "cs" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs", + label: "Čeština", + languageTag: "cs" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja", - "label": "日本語", - "languageTag": "ja" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja", + label: "日本語", + languageTag: "ja" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk", - "label": "Slovenčina", - "languageTag": "sk" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk", + label: "Slovenčina", + languageTag: "sk" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl", - "label": "Polski", - "languageTag": "pl" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl", + label: "Polski", + languageTag: "pl" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca", - "label": "Català", - "languageTag": "ca" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca", + label: "Català", + languageTag: "ca" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl", - "label": "Nederlands", - "languageTag": "nl" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl", + label: "Nederlands", + languageTag: "nl" }, { - "url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr", - "label": "Türkçe", - "languageTag": "tr" + url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr", + label: "Türkçe", + languageTag: "tr" } /* spell-checker: enable */ ], - "currentLanguageTag": "en" + currentLanguageTag: "en" }, - "features": { - "authorization": true, - "identityFederation": true, - "log": true, - "passwordUpdateSupported": true + features: { + authorization: true, + identityFederation: true, + log: true, + passwordUpdateSupported: true }, - "referrer": undefined, - "account": { - "firstName": "john", - "lastName": "doe", - "email": "john.doe@code.gouv.fr", - "username": "doe_j" + referrer: undefined, + account: { + firstName: "john", + lastName: "doe", + email: "john.doe@code.gouv.fr", + username: "doe_j" }, - "properties": { - "parent": "account-v1", - "kcButtonLargeClass": "btn-lg", - "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", - "kcButtonPrimaryClass": "btn-primary", - "accountResourceProvider": "account-v1", - "styles": - "css/account.css img/icon-sidebar-active.png img/logo.png resources-common/node_modules/patternfly/dist/css/patternfly.min.css resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css", - "kcButtonClass": "btn", - "kcButtonDefaultClass": "btn-default" + properties: { + parent: "account-v1", + kcButtonLargeClass: "btn-lg", + 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", + kcButtonPrimaryClass: "btn-primary", + accountResourceProvider: "account-v1", + styles: "css/account.css img/icon-sidebar-active.png img/logo.png resources-common/node_modules/patternfly/dist/css/patternfly.min.css resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css", + kcButtonClass: "btn", + kcButtonDefaultClass: "btn-default" } }; export const kcContextMocks: KcContext[] = [ id({ ...kcContextCommonMock, - "pageId": "password.ftl", - "password": { - "passwordSet": true + pageId: "password.ftl", + password: { + passwordSet: true }, - "stateChecker": "state checker" + stateChecker: "state checker" }), id({ ...kcContextCommonMock, - "pageId": "account.ftl", - "url": { + pageId: "account.ftl", + url: { ...kcContextCommonMock.url, - "referrerURI": "#", - "accountUrl": "#" + referrerURI: "#", + accountUrl: "#" }, - "realm": { + realm: { ...kcContextCommonMock.realm, - "registrationEmailAsUsername": true, - "editUsernameAllowed": true + registrationEmailAsUsername: true, + editUsernameAllowed: true }, - "stateChecker": "" + stateChecker: "" }), id({ ...kcContextCommonMock, - "pageId": "sessions.ftl", - "sessions": { - "sessions": [ + pageId: "sessions.ftl", + sessions: { + sessions: [ { - "ipAddress": "127.0.0.1", - "started": new Date().toString(), - "lastAccess": new Date().toString(), - "expires": new Date().toString(), - "clients": ["Chrome", "Firefox"], - "id": "f8951177-817d-4a70-9c02-86d3c170fe51" + ipAddress: "127.0.0.1", + started: new Date().toString(), + lastAccess: new Date().toString(), + expires: new Date().toString(), + clients: ["Chrome", "Firefox"], + id: "f8951177-817d-4a70-9c02-86d3c170fe51" } ] }, - "stateChecker": "g6WB1FaYnKotTkiy7ZrlxvFztSqS0U8jvHsOOOb2z4g" + stateChecker: "g6WB1FaYnKotTkiy7ZrlxvFztSqS0U8jvHsOOOb2z4g" }), id({ ...kcContextCommonMock, - "pageId": "totp.ftl", - "totp": { - "enabled": true, - "totpSecretEncoded": "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV", - "qrUrl": "#", - "totpSecretQrCode": + pageId: "totp.ftl", + totp: { + enabled: true, + totpSecretEncoded: "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV", + qrUrl: "#", + totpSecretQrCode: "iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2AQAAAADNaUdlAAACM0lEQVR4Xu3OIZJgOQwDUDFd2UxiurLAVnnbHw4YGDKtSiWOn4Gxf81//7r/+q8b4HfLGBZDK9d85NmNR+sB42sXvOYrN5P1DcgYYFTGfOlbzE8gzwy3euweGizw7cfdl34/GRhlkxjKNV+5AebPXPORX1JuB9x8ZfbyyD2y1krWAKsbMq1HnqQDaLfa77p4+MqvzEGSqvSAD/2IHW2yHaigR9tX3m8dDIYGcNf3f+gDpVBZbZU77zyJ6Rlcy+qoTMG887KAPD9hsh6a1Sv3gJUHGHUAxSMzj7zqDDe7Phmt2eG+8UsMxjRGm816MAO+8VMl1R1jGHOrZB/5Zo/WXAPgxixm9Mo96vDGrM1eOto8c4Ax4wF437mifOXlpiPzCnN7Y9l95NnEMxgMY9AAGA8fucH14Y1aVb6N/cqrmyh0BVht7k1e+bU8LK0Cg5vmVq9c5vHIjOfqxDIfeTraNVTwewa4wVe+SW5N+uP1qACeudUZbqGOfA6VZV750Noq2Xx3kpveV44ZelSV1V7KFHzkWyVrrlUwG0Pl9pWnoy3vsQoME6vKI69i5osVgwWzHT7zjmJtMcNUSVn1oYMd7ZodbgowZl45VG0uVuLPUr1yc79uaQBag/mqR34xhlWyHm1prplHboCWdZ4TeZjsK8+dI+jbz1C5hl65mcpgB5dhcj8+dGO+0Ko68+lD37JDD83dpDLzzK+TrQyaVwGj6pUboGV+7+AyN8An/pf84/7rv/4/1l4OCc/1BYMAAAAASUVORK5CYII=", - "manualUrl": "#", - "totpSecret": "G4nsI8lQagRMUchH8jEG", - "otpCredentials": [], - "supportedApplications": ["totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName"], - "policy": { - "algorithm": "HmacSHA1", - "digits": 6, - "lookAheadWindow": 1, - "type": "totp", - "period": 30 + manualUrl: "#", + totpSecret: "G4nsI8lQagRMUchH8jEG", + otpCredentials: [], + supportedApplications: [ + "totpAppFreeOTPName", + "totpAppMicrosoftAuthenticatorName", + "totpAppGoogleName" + ], + policy: { + algorithm: "HmacSHA1", + digits: 6, + lookAheadWindow: 1, + type: "totp", + period: 30 } }, - "mode": "qr", - "isAppInitiatedAction": false, - "stateChecker": "" + mode: "qr", + isAppInitiatedAction: false, + stateChecker: "" }), id({ ...kcContextCommonMock, - "pageId": "log.ftl", - "log": { - "events": [ + pageId: "log.ftl", + log: { + events: [ { - "date": "2/21/2024, 1:28:39 PM", - "event": "login", - "ipAddress": "172.17.0.1", - "client": "security-admin-console", - "details": [{ key: "openid-connect", value: "admin" }] + date: "2/21/2024, 1:28:39 PM", + event: "login", + ipAddress: "172.17.0.1", + client: "security-admin-console", + details: [{ key: "openid-connect", value: "admin" }] } ] } }), id({ ...kcContextCommonMock, - "stateChecker": "", - "pageId": "federatedIdentity.ftl", - "federatedIdentity": { - "identities": [ + stateChecker: "", + pageId: "federatedIdentity.ftl", + federatedIdentity: { + identities: [ { - "providerId": "keycloak-oidc", - "displayName": "keycloak-oidc", - "userName": "John", - "connected": true + providerId: "keycloak-oidc", + displayName: "keycloak-oidc", + userName: "John", + connected: true } ], - "removeLinkPossible": true + removeLinkPossible: true } }) ]; diff --git a/src/account/lib/useGetClassName.ts b/src/account/lib/useGetClassName.ts index 15397ade..ab0216da 100644 --- a/src/account/lib/useGetClassName.ts +++ b/src/account/lib/useGetClassName.ts @@ -2,19 +2,20 @@ import { createUseClassName } from "keycloakify/lib/useGetClassName"; import type { ClassKey } from "keycloakify/account/TemplateProps"; export const { useGetClassName } = createUseClassName({ - "defaultClasses": { - "kcHtmlClass": undefined, - "kcBodyClass": undefined, - "kcButtonClass": "btn", - "kcContentWrapperClass": "row", - "kcButtonPrimaryClass": "btn-primary", - "kcButtonLargeClass": "btn-lg", - "kcButtonDefaultClass": "btn-default", - "kcFormClass": "form-horizontal", - "kcFormGroupClass": "form-group", - "kcInputWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12", - "kcLabelClass": "control-label", - "kcInputClass": "form-control", - "kcInputErrorMessageClass": "pf-c-form__helper-text pf-m-error required kc-feedback-text" + defaultClasses: { + kcHtmlClass: undefined, + kcBodyClass: undefined, + kcButtonClass: "btn", + kcContentWrapperClass: "row", + kcButtonPrimaryClass: "btn-primary", + kcButtonLargeClass: "btn-lg", + kcButtonDefaultClass: "btn-default", + kcFormClass: "form-horizontal", + kcFormGroupClass: "form-group", + kcInputWrapperClass: "col-xs-12 col-sm-12 col-md-12 col-lg-12", + kcLabelClass: "control-label", + kcInputClass: "form-control", + kcInputErrorMessageClass: + "pf-c-form__helper-text pf-m-error required kc-feedback-text" } }); diff --git a/src/account/pages/Account.tsx b/src/account/pages/Account.tsx index a93f20e4..97465db0 100644 --- a/src/account/pages/Account.tsx +++ b/src/account/pages/Account.tsx @@ -9,9 +9,9 @@ export default function Account(props: PageProps { + message: (() => { if (newPasswordError !== "") { return { - "type": "error", - "summary": newPasswordError + type: "error", + summary: newPasswordError }; } if (newPasswordConfirmError !== "") { return { - "type": "error", - "summary": newPasswordConfirmError + type: "error", + summary: newPasswordConfirmError }; } @@ -98,7 +98,7 @@ export default function Password(props: PageProps {password.passwordSet && ( diff --git a/src/account/pages/Totp.tsx b/src/account/pages/Totp.tsx index 201d11d6..22946b5e 100644 --- a/src/account/pages/Totp.tsx +++ b/src/account/pages/Totp.tsx @@ -18,9 +18,9 @@ export default function Totp(props: PageProps = { - "HmacSHA1": "SHA1", - "HmacSHA256": "SHA256", - "HmacSHA512": "SHA512" + HmacSHA1: "SHA1", + HmacSHA256: "SHA256", + HmacSHA512: "SHA512" }; return ( diff --git a/src/bin/copy-keycloak-resources-to-public.ts b/src/bin/copy-keycloak-resources-to-public.ts index 8bc4abf9..d6fbcac3 100644 --- a/src/bin/copy-keycloak-resources-to-public.ts +++ b/src/bin/copy-keycloak-resources-to-public.ts @@ -8,9 +8,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const buildOptions = readBuildOptions({ cliCommandOptions }); await copyKeycloakResourcesToPublic({ - "buildOptions": { + buildOptions: { ...buildOptions, - "publicDirPath": buildOptions.reactAppRootDirPath + publicDirPath: buildOptions.reactAppRootDirPath } }); } diff --git a/src/bin/download-keycloak-default-theme.ts b/src/bin/download-keycloak-default-theme.ts index 799e2f1b..8d787b2c 100644 --- a/src/bin/download-keycloak-default-theme.ts +++ b/src/bin/download-keycloak-default-theme.ts @@ -12,22 +12,39 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) cliCommandOptions }); - console.log(chalk.cyan("Select the Keycloak version from which you want to download the builtins theme:")); + console.log( + chalk.cyan( + "Select the Keycloak version from which you want to download the builtins theme:" + ) + ); const { keycloakVersion } = await promptKeycloakVersion({ - "startingFromMajor": undefined, - "cacheDirPath": buildOptions.cacheDirPath + startingFromMajor: undefined, + cacheDirPath: buildOptions.cacheDirPath }); console.log(`→ ${keycloakVersion}`); - const destDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme"); + const destDirPath = pathJoin( + buildOptions.keycloakifyBuildDirPath, + "src", + "main", + "resources", + "theme" + ); console.log( [ `Downloading builtins theme of Keycloak ${keycloakVersion} here:`, - `- ${chalk.bold(`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "base")}`)}`, - `- ${chalk.bold(`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "keycloak")}`)}` + `- ${chalk.bold( + `.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "base")}` + )}`, + `- ${chalk.bold( + `.${pathSep}${pathJoin( + pathRelative(process.cwd(), destDirPath), + "keycloak" + )}` + )}` ].join("\n") ); diff --git a/src/bin/eject-page.ts b/src/bin/eject-page.ts index 3b34f9b3..c0b805fb 100644 --- a/src/bin/eject-page.ts +++ b/src/bin/eject-page.ts @@ -30,7 +30,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) console.log(chalk.cyan("Theme type:")); const { value: themeType } = await cliSelect({ - "values": [...themeTypes] + values: [...themeTypes] }).catch(() => { process.exit(-1); }); @@ -40,7 +40,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) console.log(chalk.cyan("Select the page you want to customize:")); const { value: pageId } = await cliSelect({ - "values": (() => { + values: (() => { switch (themeType) { case "login": return [...loginThemePageIds]; @@ -55,14 +55,29 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) console.log(`→ ${pageId}`); - const componentPageBasename = capitalize(kebabCaseToCamelCase(pageId)).replace(/ftl$/, "tsx"); + const componentPageBasename = capitalize(kebabCaseToCamelCase(pageId)).replace( + /ftl$/, + "tsx" + ); - const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath }); + const { themeSrcDirPath } = getThemeSrcDirPath({ + reactAppRootDirPath: buildOptions.reactAppRootDirPath + }); - const targetFilePath = pathJoin(themeSrcDirPath, themeType, "pages", componentPageBasename); + const targetFilePath = pathJoin( + themeSrcDirPath, + themeType, + "pages", + componentPageBasename + ); if (fs.existsSync(targetFilePath)) { - console.log(`${pageId} is already ejected, ${pathRelative(process.cwd(), targetFilePath)} already exists`); + console.log( + `${pageId} is already ejected, ${pathRelative( + process.cwd(), + targetFilePath + )} already exists` + ); process.exit(-1); } @@ -71,12 +86,20 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const targetDirPath = pathDirname(targetFilePath); if (!fs.existsSync(targetDirPath)) { - fs.mkdirSync(targetDirPath, { "recursive": true }); + fs.mkdirSync(targetDirPath, { recursive: true }); } } const componentPageContent = fs - .readFileSync(pathJoin(getThisCodebaseRootDirPath(), "src", themeType, "pages", componentPageBasename)) + .readFileSync( + pathJoin( + getThisCodebaseRootDirPath(), + "src", + themeType, + "pages", + componentPageBasename + ) + ) .toString("utf8"); fs.writeFileSync(targetFilePath, Buffer.from(componentPageContent, "utf8")); @@ -92,11 +115,23 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) ``, `You now need to update your page router:`, ``, - `${chalk.bold(pathJoin(".", pathRelative(process.cwd(), themeSrcDirPath), themeType, "KcApp.tsx"))}:`, + `${chalk.bold( + pathJoin( + ".", + pathRelative(process.cwd(), themeSrcDirPath), + themeType, + "KcApp.tsx" + ) + )}:`, chalk.grey("```"), `// ...`, ``, - chalk.green(`+const ${componentPageBasename.replace(/.tsx$/, "")} = lazy(() => import("./pages/${componentPageBasename}"));`), + chalk.green( + `+const ${componentPageBasename.replace( + /.tsx$/, + "" + )} = lazy(() => import("./pages/${componentPageBasename}"));` + ), ...[ ``, ` export default function KcApp(props: { kcContext: KcContext; }) {`, @@ -114,7 +149,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) `+ Template={Template}`, ...(!componentPageContent.includes(userProfileFormFieldComponentName) ? [] - : [`+ ${userProfileFormFieldComponentName}={${userProfileFormFieldComponentName}}`]), + : [ + `+ ${userProfileFormFieldComponentName}={${userProfileFormFieldComponentName}}` + ]), `+ doUseDefaultCss={true}`, `+ />`, `+ );`, diff --git a/src/bin/initialize-email-theme.ts b/src/bin/initialize-email-theme.ts index f7bdb32f..d915e2b0 100644 --- a/src/bin/initialize-email-theme.ts +++ b/src/bin/initialize-email-theme.ts @@ -14,13 +14,18 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const buildOptions = readBuildOptions({ cliCommandOptions }); const { themeSrcDirPath } = getThemeSrcDirPath({ - "reactAppRootDirPath": buildOptions.reactAppRootDirPath + reactAppRootDirPath: buildOptions.reactAppRootDirPath }); const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email"); if (fs.existsSync(emailThemeSrcDirPath)) { - console.warn(`There is already a ${pathRelative(process.cwd(), emailThemeSrcDirPath)} directory in your project. Aborting.`); + console.warn( + `There is already a ${pathRelative( + process.cwd(), + emailThemeSrcDirPath + )} directory in your project. Aborting.` + ); process.exit(-1); } @@ -29,33 +34,50 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const { keycloakVersion } = await promptKeycloakVersion({ // NOTE: This is arbitrary - "startingFromMajor": 17, - "cacheDirPath": buildOptions.cacheDirPath + startingFromMajor: 17, + cacheDirPath: buildOptions.cacheDirPath }); - const builtinKeycloakThemeTmpDirPath = pathJoin(buildOptions.cacheDirPath, "initialize-email-theme_tmp"); + const builtinKeycloakThemeTmpDirPath = pathJoin( + buildOptions.cacheDirPath, + "initialize-email-theme_tmp" + ); - rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true, "force": true }); + rmSync(builtinKeycloakThemeTmpDirPath, { + recursive: true, + force: true + }); await downloadKeycloakDefaultTheme({ keycloakVersion, - "destDirPath": builtinKeycloakThemeTmpDirPath, + destDirPath: builtinKeycloakThemeTmpDirPath, buildOptions }); transformCodebase({ - "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"), - "destDirPath": emailThemeSrcDirPath + srcDirPath: pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"), + destDirPath: emailThemeSrcDirPath }); { const themePropertyFilePath = pathJoin(emailThemeSrcDirPath, "theme.properties"); - fs.writeFileSync(themePropertyFilePath, Buffer.from(`parent=base\n${fs.readFileSync(themePropertyFilePath).toString("utf8")}`, "utf8")); + fs.writeFileSync( + themePropertyFilePath, + Buffer.from( + `parent=base\n${fs.readFileSync(themePropertyFilePath).toString("utf8")}`, + "utf8" + ) + ); } - console.log(`The \`${pathJoin(".", pathRelative(process.cwd(), emailThemeSrcDirPath))}\` directory have been created.`); + console.log( + `The \`${pathJoin( + ".", + pathRelative(process.cwd(), emailThemeSrcDirPath) + )}\` directory have been created.` + ); console.log("You can delete any file you don't modify."); - rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true }); + rmSync(builtinKeycloakThemeTmpDirPath, { recursive: true }); } diff --git a/src/bin/keycloakify/buildJars/buildJar.ts b/src/bin/keycloakify/buildJars/buildJar.ts index be121e03..f47b642d 100644 --- a/src/bin/keycloakify/buildJars/buildJar.ts +++ b/src/bin/keycloakify/buildJars/buildJar.ts @@ -1,11 +1,17 @@ import { assert, type Equals } from "tsafe/assert"; -import type { KeycloakAccountV1Version, KeycloakThemeAdditionalInfoExtensionVersion } from "./extensionVersions"; +import type { + KeycloakAccountV1Version, + KeycloakThemeAdditionalInfoExtensionVersion +} from "./extensionVersions"; import { join as pathJoin, dirname as pathDirname } from "path"; import { transformCodebase } from "../../tools/transformCodebase"; import type { BuildOptions } from "../../shared/buildOptions"; import * as fs from "fs/promises"; import { accountV1ThemeName } from "../../shared/constants"; -import { generatePom, BuildOptionsLike as BuildOptionsLike_generatePom } from "./generatePom"; +import { + generatePom, + BuildOptionsLike as BuildOptionsLike_generatePom +} from "./generatePom"; import { readFileSync } from "fs"; import { isInside } from "../../tools/isInside"; import child_process from "child_process"; @@ -29,26 +35,53 @@ export async function buildJar(params: { keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion; buildOptions: BuildOptionsLike; }): Promise { - const { jarFileBasename, keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, buildOptions } = params; + const { + jarFileBasename, + keycloakAccountV1Version, + keycloakThemeAdditionalInfoExtensionVersion, + buildOptions + } = params; - const keycloakifyBuildTmpDirPath = pathJoin(buildOptions.cacheDirPath, jarFileBasename.replace(".jar", "")); + const keycloakifyBuildTmpDirPath = pathJoin( + buildOptions.cacheDirPath, + jarFileBasename.replace(".jar", "") + ); - rmSync(keycloakifyBuildTmpDirPath, { "recursive": true, "force": true }); + rmSync(keycloakifyBuildTmpDirPath, { recursive: true, force: true }); { - const metaInfKeycloakThemesJsonRelativePath = getMetaInfKeycloakThemesJsonFilePath({ "keycloakifyBuildDirPath": "" }); + const metaInfKeycloakThemesJsonRelativePath = + getMetaInfKeycloakThemesJsonFilePath({ + keycloakifyBuildDirPath: "" + }); const { transformCodebase_common } = (() => { - const includingAccountV1ThemeNames = [...buildOptions.themeNames, accountV1ThemeName]; + const includingAccountV1ThemeNames = [ + ...buildOptions.themeNames, + accountV1ThemeName + ]; - const transformCodebase_common: Param0["transformSourceCode"] = ({ fileRelativePath, sourceCode }) => { + const transformCodebase_common: Param0< + typeof transformCodebase + >["transformSourceCode"] = ({ fileRelativePath, sourceCode }) => { if (metaInfKeycloakThemesJsonRelativePath === fileRelativePath) { - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } for (const themeName of includingAccountV1ThemeNames) { - if (isInside({ "dirPath": pathJoin("src", "main", "resources", "theme", themeName), "filePath": fileRelativePath })) { - return { "modifiedSourceCode": sourceCode }; + if ( + isInside({ + dirPath: pathJoin( + "src", + "main", + "resources", + "theme", + themeName + ), + filePath: fileRelativePath + }) + ) { + return { modifiedSourceCode: sourceCode }; } } @@ -60,36 +93,70 @@ export async function buildJar(params: { const { transformCodebase_patchForUsingBuiltinAccountV1 } = (() => { if (keycloakAccountV1Version !== null) { - return { "transformCodebase_patchForUsingBuiltinAccountV1": undefined }; + return { + transformCodebase_patchForUsingBuiltinAccountV1: undefined + }; } const themePropertiesFileRelativePathSet = new Set( - ...buildOptions.themeNames.map(themeName => pathJoin("src", "main", "resources", "theme", themeName, "account", "theme.properties")) + ...buildOptions.themeNames.map(themeName => + pathJoin( + "src", + "main", + "resources", + "theme", + themeName, + "account", + "theme.properties" + ) + ) ); - const accountV1RelativeDirPath = pathJoin("src", "main", "resources", "theme", accountV1ThemeName); + const accountV1RelativeDirPath = pathJoin( + "src", + "main", + "resources", + "theme", + accountV1ThemeName + ); - const transformCodebase_patchForUsingBuiltinAccountV1: Param0["transformSourceCode"] = ({ - fileRelativePath, - sourceCode - }) => { - if (isInside({ "dirPath": accountV1RelativeDirPath, "filePath": fileRelativePath })) { + const transformCodebase_patchForUsingBuiltinAccountV1: Param0< + typeof transformCodebase + >["transformSourceCode"] = ({ fileRelativePath, sourceCode }) => { + if ( + isInside({ + dirPath: accountV1RelativeDirPath, + filePath: fileRelativePath + }) + ) { return undefined; } if (fileRelativePath === metaInfKeycloakThemesJsonRelativePath) { - const keycloakThemesJsonParsed = JSON.parse(sourceCode.toString("utf8")) as { + const keycloakThemesJsonParsed = JSON.parse( + sourceCode.toString("utf8") + ) as { themes: { name: string; types: string[] }[]; }; - keycloakThemesJsonParsed.themes = keycloakThemesJsonParsed.themes.filter(({ name }) => name !== accountV1ThemeName); + keycloakThemesJsonParsed.themes = + keycloakThemesJsonParsed.themes.filter( + ({ name }) => name !== accountV1ThemeName + ); - return { "modifiedSourceCode": Buffer.from(JSON.stringify(keycloakThemesJsonParsed, null, 2), "utf8") }; + return { + modifiedSourceCode: Buffer.from( + JSON.stringify(keycloakThemesJsonParsed, null, 2), + "utf8" + ) + }; } if (themePropertiesFileRelativePathSet.has(fileRelativePath)) { const modifiedSourceCode = Buffer.from( - sourceCode.toString("utf8").replace(`parent=${accountV1ThemeName}`, "parent=keycloak"), + sourceCode + .toString("utf8") + .replace(`parent=${accountV1ThemeName}`, "parent=keycloak"), "utf8" ); @@ -99,16 +166,16 @@ export async function buildJar(params: { return { modifiedSourceCode }; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; }; return { transformCodebase_patchForUsingBuiltinAccountV1 }; })(); transformCodebase({ - "srcDirPath": buildOptions.keycloakifyBuildDirPath, - "destDirPath": keycloakifyBuildTmpDirPath, - "transformSourceCode": params => { + srcDirPath: buildOptions.keycloakifyBuildDirPath, + destDirPath: keycloakifyBuildTmpDirPath, + transformSourceCode: params => { const resultCommon = transformCodebase_common(params); if (resultCommon === undefined) { @@ -125,7 +192,7 @@ export async function buildJar(params: { return transformCodebase_patchForUsingBuiltinAccountV1?.({ ...params, - "sourceCode": modifiedSourceCode + sourceCode: modifiedSourceCode }); } }); @@ -152,7 +219,16 @@ export async function buildJar(params: { (["register.ftl", "login-update-profile.ftl"] as const).forEach(pageId => buildOptions.themeNames.map(themeName => { - const ftlFilePath = pathJoin(keycloakifyBuildTmpDirPath, "src", "main", "resources", "theme", themeName, "login", pageId); + const ftlFilePath = pathJoin( + keycloakifyBuildTmpDirPath, + "src", + "main", + "resources", + "theme", + themeName, + "login", + pageId + ); const ftlFileContent = readFileSync(ftlFilePath).toString("utf8"); @@ -173,7 +249,10 @@ export async function buildJar(params: { assert(modifiedFtlFileContent !== ftlFileContent); - fs.writeFile(pathJoin(pathDirname(ftlFilePath), realPageId), Buffer.from(modifiedFtlFileContent, "utf8")); + fs.writeFile( + pathJoin(pathDirname(ftlFilePath), realPageId), + Buffer.from(modifiedFtlFileContent, "utf8") + ); }) ); } @@ -185,35 +264,46 @@ export async function buildJar(params: { keycloakThemeAdditionalInfoExtensionVersion }); - await fs.writeFile(pathJoin(keycloakifyBuildTmpDirPath, "pom.xml"), Buffer.from(pomFileCode, "utf8")); + await fs.writeFile( + pathJoin(keycloakifyBuildTmpDirPath, "pom.xml"), + Buffer.from(pomFileCode, "utf8") + ); } await new Promise((resolve, reject) => - child_process.exec("mvn clean install", { "cwd": keycloakifyBuildTmpDirPath }, error => { - if (error !== null) { - console.error( - `Build jar failed: ${JSON.stringify( - { - jarFileBasename, - keycloakAccountV1Version, - keycloakThemeAdditionalInfoExtensionVersion - }, - null, - 2 - )}` - ); + child_process.exec( + "mvn clean install", + { cwd: keycloakifyBuildTmpDirPath }, + error => { + if (error !== null) { + console.error( + `Build jar failed: ${JSON.stringify( + { + jarFileBasename, + keycloakAccountV1Version, + keycloakThemeAdditionalInfoExtensionVersion + }, + null, + 2 + )}` + ); - reject(error); - return; + reject(error); + return; + } + resolve(); } - resolve(); - }) + ) ); await fs.rename( - pathJoin(keycloakifyBuildTmpDirPath, "target", `${buildOptions.artifactId}-${buildOptions.themeVersion}.jar`), + pathJoin( + keycloakifyBuildTmpDirPath, + "target", + `${buildOptions.artifactId}-${buildOptions.themeVersion}.jar` + ), pathJoin(buildOptions.keycloakifyBuildDirPath, jarFileBasename) ); - rmSync(keycloakifyBuildTmpDirPath, { "recursive": true }); + rmSync(keycloakifyBuildTmpDirPath, { recursive: true }); } diff --git a/src/bin/keycloakify/buildJars/buildJars.ts b/src/bin/keycloakify/buildJars/buildJars.ts index d16874de..05d3aecc 100644 --- a/src/bin/keycloakify/buildJars/buildJars.ts +++ b/src/bin/keycloakify/buildJars/buildJars.ts @@ -1,6 +1,9 @@ import { assert } from "tsafe/assert"; import { exclude } from "tsafe/exclude"; -import { keycloakAccountV1Versions, keycloakThemeAdditionalInfoExtensionVersions } from "./extensionVersions"; +import { + keycloakAccountV1Versions, + keycloakThemeAdditionalInfoExtensionVersions +} from "./extensionVersions"; import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar"; import { buildJar, BuildOptionsLike as BuildOptionsLike_buildJar } from "./buildJar"; import type { BuildOptions } from "../../shared/buildOptions"; @@ -14,11 +17,13 @@ export type BuildOptionsLike = BuildOptionsLike_buildJar & { assert(); -export async function buildJars(params: { buildOptions: BuildOptionsLike }): Promise { +export async function buildJars(params: { + buildOptions: BuildOptionsLike; +}): Promise { const { buildOptions } = params; const doesImplementAccountTheme = readMetaInfKeycloakThemes({ - "keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath + keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath }).themes.some(({ name }) => name === accountV1ThemeName); await Promise.all( @@ -36,24 +41,38 @@ export async function buildJars(params: { buildOptions: BuildOptionsLike }): Pro return undefined; } - return { keycloakThemeAdditionalInfoExtensionVersion, keycloakVersionRange }; - }) - .filter(exclude(undefined)) - .map(({ keycloakThemeAdditionalInfoExtensionVersion, keycloakVersionRange }) => { - const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange }); - return { keycloakThemeAdditionalInfoExtensionVersion, - jarFileBasename + keycloakVersionRange }; }) - .map(({ keycloakThemeAdditionalInfoExtensionVersion, jarFileBasename }) => - buildJar({ - jarFileBasename, - keycloakAccountV1Version, + .filter(exclude(undefined)) + .map( + ({ keycloakThemeAdditionalInfoExtensionVersion, - buildOptions - }) + keycloakVersionRange + }) => { + const { jarFileBasename } = getJarFileBasename({ + keycloakVersionRange + }); + + return { + keycloakThemeAdditionalInfoExtensionVersion, + jarFileBasename + }; + } + ) + .map( + ({ + keycloakThemeAdditionalInfoExtensionVersion, + jarFileBasename + }) => + buildJar({ + jarFileBasename, + keycloakAccountV1Version, + keycloakThemeAdditionalInfoExtensionVersion, + buildOptions + }) ) ) .flat() diff --git a/src/bin/keycloakify/buildJars/extensionVersions.ts b/src/bin/keycloakify/buildJars/extensionVersions.ts index 8b9b1b01..b030e54d 100644 --- a/src/bin/keycloakify/buildJars/extensionVersions.ts +++ b/src/bin/keycloakify/buildJars/extensionVersions.ts @@ -13,4 +13,5 @@ export const keycloakThemeAdditionalInfoExtensionVersions = [null, "1.1.5"] as c * https://central.sonatype.com/artifact/dev.jcputney/keycloak-theme-additional-info-extension * https://github.com/jcputney/keycloak-theme-additional-info-extension * */ -export type KeycloakThemeAdditionalInfoExtensionVersion = (typeof keycloakThemeAdditionalInfoExtensionVersions)[number]; +export type KeycloakThemeAdditionalInfoExtensionVersion = + (typeof keycloakThemeAdditionalInfoExtensionVersions)[number]; diff --git a/src/bin/keycloakify/buildJars/generatePom.ts b/src/bin/keycloakify/buildJars/generatePom.ts index 13fa4cf0..e28ed841 100644 --- a/src/bin/keycloakify/buildJars/generatePom.ts +++ b/src/bin/keycloakify/buildJars/generatePom.ts @@ -1,6 +1,9 @@ import { assert } from "tsafe/assert"; import type { BuildOptions } from "../../shared/buildOptions"; -import type { KeycloakAccountV1Version, KeycloakThemeAdditionalInfoExtensionVersion } from "./extensionVersions"; +import type { + KeycloakAccountV1Version, + KeycloakThemeAdditionalInfoExtensionVersion +} from "./extensionVersions"; export type BuildOptionsLike = { groupId: string; @@ -15,7 +18,11 @@ export function generatePom(params: { keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion; buildOptions: BuildOptionsLike; }) { - const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, buildOptions } = params; + const { + keycloakAccountV1Version, + keycloakThemeAdditionalInfoExtensionVersion, + buildOptions + } = params; const { pomFileCode } = (function generatePomFileCode(): { pomFileCode: string; @@ -35,7 +42,8 @@ export function generatePom(params: { ` `, ` UTF-8`, ` `, - ...(keycloakAccountV1Version !== null && keycloakThemeAdditionalInfoExtensionVersion !== null + ...(keycloakAccountV1Version !== null && + keycloakThemeAdditionalInfoExtensionVersion !== null ? [ ` `, ` `, diff --git a/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts b/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts index 6dc7b49f..41924c6c 100644 --- a/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts +++ b/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts @@ -1,5 +1,8 @@ import { assert, type Equals } from "tsafe/assert"; -import type { KeycloakAccountV1Version, KeycloakThemeAdditionalInfoExtensionVersion } from "./extensionVersions"; +import type { + KeycloakAccountV1Version, + KeycloakThemeAdditionalInfoExtensionVersion +} from "./extensionVersions"; import type { KeycloakVersionRange } from "../../shared/KeycloakVersionRange"; export function getKeycloakVersionRangeForJar(params: { @@ -7,7 +10,11 @@ export function getKeycloakVersionRangeForJar(params: { keycloakAccountV1Version: KeycloakAccountV1Version; keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion; }): KeycloakVersionRange | undefined { - const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doesImplementAccountTheme } = params; + const { + keycloakAccountV1Version, + keycloakThemeAdditionalInfoExtensionVersion, + doesImplementAccountTheme + } = params; if (doesImplementAccountTheme) { const keycloakVersionRange = (() => { @@ -19,7 +26,9 @@ export function getKeycloakVersionRangeForJar(params: { case "1.1.5": return undefined; } - assert>(false); + assert< + Equals + >(false); case "0.3": switch (keycloakThemeAdditionalInfoExtensionVersion) { case null: @@ -27,7 +36,9 @@ export function getKeycloakVersionRangeForJar(params: { case "1.1.5": return "23" as const; } - assert>(false); + assert< + Equals + >(false); case "0.4": switch (keycloakThemeAdditionalInfoExtensionVersion) { case null: @@ -35,11 +46,18 @@ export function getKeycloakVersionRangeForJar(params: { case "1.1.5": return "24-and-above" as const; } - assert>(false); + assert< + Equals + >(false); } })(); - assert>(); + assert< + Equals< + typeof keycloakVersionRange, + KeycloakVersionRange.WithAccountTheme | undefined + > + >(); return keycloakVersionRange; } else { @@ -54,10 +72,17 @@ export function getKeycloakVersionRangeForJar(params: { case "1.1.5": return "22-and-above"; } - assert>(false); + assert>( + false + ); })(); - assert>(); + assert< + Equals< + typeof keycloakVersionRange, + KeycloakVersionRange.WithoutAccountTheme | undefined + > + >(); return keycloakVersionRange; } diff --git a/src/bin/keycloakify/generateFtl/generateFtl.ts b/src/bin/keycloakify/generateFtl/generateFtl.ts index 97e70ece..bca110bd 100644 --- a/src/bin/keycloakify/generateFtl/generateFtl.ts +++ b/src/bin/keycloakify/generateFtl/generateFtl.ts @@ -6,7 +6,12 @@ import * as fs from "fs"; import { join as pathJoin } from "path"; import type { BuildOptions } from "../../shared/buildOptions"; import { assert } from "tsafe/assert"; -import { type ThemeType, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir, resources_common } from "../../shared/constants"; +import { + type ThemeType, + nameOfTheGlobal, + basenameOfTheKeycloakifyResourcesDir, + resources_common +} from "../../shared/constants"; import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath"; export type BuildOptionsLike = { @@ -28,7 +33,15 @@ export function generateFtlFilesCodeFactory(params: { themeType: ThemeType; fieldNames: string[]; }) { - const { themeName, cssGlobalsToDefine, indexHtmlCode, buildOptions, keycloakifyVersion, themeType, fieldNames } = params; + const { + themeName, + cssGlobalsToDefine, + indexHtmlCode, + buildOptions, + keycloakifyVersion, + themeType, + fieldNames + } = params; const $ = cheerio.load(indexHtmlCode); @@ -38,7 +51,10 @@ export function generateFtlFilesCodeFactory(params: { assert(jsCode !== null); - const { fixedJsCode } = replaceImportsInJsCode({ jsCode, buildOptions }); + const { fixedJsCode } = replaceImportsInJsCode({ + jsCode, + buildOptions + }); $(element).text(fixedJsCode); }); @@ -72,7 +88,9 @@ export function generateFtlFilesCodeFactory(params: { $(element).attr( attrName, href.replace( - new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`), + new RegExp( + `^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}` + ), `\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/` ) ); @@ -98,20 +116,33 @@ export function generateFtlFilesCodeFactory(params: { //FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later. const ftlObjectToJsCodeDeclaringAnObject = fs .readFileSync( - pathJoin(getThisCodebaseRootDirPath(), "src", "bin", "keycloakify", "generateFtl", "ftl_object_to_js_code_declaring_an_object.ftl") + pathJoin( + getThisCodebaseRootDirPath(), + "src", + "bin", + "keycloakify", + "generateFtl", + "ftl_object_to_js_code_declaring_an_object.ftl" + ) ) .toString("utf8") .match(/^`); + $("head").prepend( + `` + ); // Remove part of the document marked as ignored. { @@ -119,7 +150,9 @@ export function generateFtlFilesCodeFactory(params: { startTags.each((...[, startTag]) => { const $startTag = $(startTag); - const $endTag = $startTag.nextAll('meta[name="keycloakify-ignore-end"]').first(); + const $endTag = $startTag + .nextAll('meta[name="keycloakify-ignore-end"]') + .first(); if ($endTag.length) { let currentNode = $startTag.next(); @@ -146,9 +179,13 @@ export function generateFtlFilesCodeFactory(params: { let ftlCode = $.html(); Object.entries({ - [ftlObjectToJsCodeDeclaringAnObjectPlaceholder]: ftlObjectToJsCodeDeclaringAnObject, - "PAGE_ID_xIgLsPgGId9D8e": pageId - }).map(([searchValue, replaceValue]) => (ftlCode = ftlCode.replace(searchValue, replaceValue))); + [ftlObjectToJsCodeDeclaringAnObjectPlaceholder]: + ftlObjectToJsCodeDeclaringAnObject, + PAGE_ID_xIgLsPgGId9D8e: pageId + }).map( + ([searchValue, replaceValue]) => + (ftlCode = ftlCode.replace(searchValue, replaceValue)) + ); return { ftlCode }; } diff --git a/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts b/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts index 536675df..687f6437 100644 --- a/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts +++ b/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts @@ -2,7 +2,11 @@ import * as fs from "fs"; import { join as pathJoin } from "path"; import { assert } from "tsafe/assert"; import type { BuildOptions } from "../../shared/buildOptions"; -import { resources_common, lastKeycloakVersionWithAccountV1, accountV1ThemeName } from "../../shared/constants"; +import { + resources_common, + lastKeycloakVersionWithAccountV1, + accountV1ThemeName +} from "../../shared/constants"; import { downloadKeycloakDefaultTheme } from "../../shared/downloadKeycloakDefaultTheme"; import { transformCodebase } from "../../tools/transformCodebase"; import { rmSync } from "../../tools/fs.rmSync"; @@ -18,32 +22,53 @@ assert(); export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike }) { const { buildOptions } = params; - const builtinKeycloakThemeTmpDirPath = pathJoin(buildOptions.cacheDirPath, "bringInAccountV1_tmp"); + const builtinKeycloakThemeTmpDirPath = pathJoin( + buildOptions.cacheDirPath, + "bringInAccountV1_tmp" + ); await downloadKeycloakDefaultTheme({ - "destDirPath": builtinKeycloakThemeTmpDirPath, - "keycloakVersion": lastKeycloakVersionWithAccountV1, + destDirPath: builtinKeycloakThemeTmpDirPath, + keycloakVersion: lastKeycloakVersionWithAccountV1, buildOptions }); - const accountV1DirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", accountV1ThemeName, "account"); + const accountV1DirPath = pathJoin( + buildOptions.keycloakifyBuildDirPath, + "src", + "main", + "resources", + "theme", + accountV1ThemeName, + "account" + ); transformCodebase({ - "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"), - "destDirPath": accountV1DirPath + srcDirPath: pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"), + destDirPath: accountV1DirPath }); transformCodebase({ - "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "keycloak", "account", "resources"), - "destDirPath": pathJoin(accountV1DirPath, "resources") + srcDirPath: pathJoin( + builtinKeycloakThemeTmpDirPath, + "keycloak", + "account", + "resources" + ), + destDirPath: pathJoin(accountV1DirPath, "resources") }); transformCodebase({ - "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "keycloak", "common", "resources"), - "destDirPath": pathJoin(accountV1DirPath, "resources", resources_common) + srcDirPath: pathJoin( + builtinKeycloakThemeTmpDirPath, + "keycloak", + "common", + "resources" + ), + destDirPath: pathJoin(accountV1DirPath, "resources", resources_common) }); - rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true }); + rmSync(builtinKeycloakThemeTmpDirPath, { recursive: true }); fs.writeFileSync( pathJoin(accountV1DirPath, "theme.properties"), @@ -58,8 +83,13 @@ export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike "css/account.css", "img/icon-sidebar-active.png", "img/logo.png", - ...["patternfly.min.css", "patternfly-additions.min.css", "patternfly-additions.min.css"].map( - fileBasename => `${resources_common}/node_modules/patternfly/dist/css/${fileBasename}` + ...[ + "patternfly.min.css", + "patternfly-additions.min.css", + "patternfly-additions.min.css" + ].map( + fileBasename => + `${resources_common}/node_modules/patternfly/dist/css/${fileBasename}` ) ].join(" "), "", diff --git a/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts b/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts index 053c4f72..3d5f2ccc 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts @@ -16,8 +16,8 @@ export function generateMessageProperties(params: { const { themeSrcDirPath, themeType } = params; let files = crawl({ - "dirPath": pathJoin(themeSrcDirPath, themeType), - "returnedPathsType": "absolute" + dirPath: pathJoin(themeSrcDirPath, themeType), + returnedPathsType: "absolute" }); files = files.filter(file => { @@ -34,7 +34,9 @@ export function generateMessageProperties(params: { files = files.sort((a, b) => a.length - b.length); - files = files.filter(file => readFileSync(file).toString("utf8").includes("createUseI18n")); + files = files.filter(file => + readFileSync(file).toString("utf8").includes("createUseI18n") + ); if (files.length === 0) { return []; @@ -43,18 +45,25 @@ export function generateMessageProperties(params: { const extraMessages = files .map(file => { const root = recast.parse(readFileSync(file).toString("utf8"), { - "parser": { - "parse": (code: string) => babelParser.parse(code, { "sourceType": "module", "plugins": ["typescript"] }), - "generator": babelGenerate, - "types": babelTypes + parser: { + parse: (code: string) => + babelParser.parse(code, { + sourceType: "module", + plugins: ["typescript"] + }), + generator: babelGenerate, + types: babelTypes } }); const codes: string[] = []; recast.visit(root, { - "visitCallExpression": function (path) { - if (path.node.callee.type === "Identifier" && path.node.callee.name === "createUseI18n") { + visitCallExpression: function (path) { + if ( + path.node.callee.type === "Identifier" && + path.node.callee.name === "createUseI18n" + ) { codes.push(babelGenerate(path.node.arguments[0] as any).code); } this.traverse(path); @@ -65,7 +74,9 @@ export function generateMessageProperties(params: { }) .flat() .map(code => { - let extraMessages: { [languageTag: string]: Record } = {}; + let extraMessages: { + [languageTag: string]: Record; + } = {}; try { eval(`${symToStr({ extraMessages })} = ${code}`); @@ -140,7 +151,14 @@ export function generateMessageProperties(params: { out.push({ languageTag, - "propertiesFileSource": ["# This file was generated by keycloakify", "", "parent=base", "", propertiesFileSource, ""].join("\n") + propertiesFileSource: [ + "# This file was generated by keycloakify", + "", + "parent=base", + "", + propertiesFileSource, + "" + ].join("\n") }); } @@ -157,7 +175,12 @@ function toUTF16(codePoint: number): string { codePoint -= 0x10000; let highSurrogate = (codePoint >> 10) + 0xd800; let lowSurrogate = (codePoint % 0x400) + 0xdc00; - return "\\u" + highSurrogate.toString(16).padStart(4, "0") + "\\u" + lowSurrogate.toString(16).padStart(4, "0"); + return ( + "\\u" + + highSurrogate.toString(16).padStart(4, "0") + + "\\u" + + lowSurrogate.toString(16).padStart(4, "0") + ); } } diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts index 01865235..bf0e6f5d 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts @@ -12,7 +12,9 @@ export type BuildOptionsLike = BuildOptionsLike_generateSrcMainResourcesForMainT assert(); -export async function generateSrcMainResources(params: { buildOptions: BuildOptionsLike }): Promise { +export async function generateSrcMainResources(params: { + buildOptions: BuildOptionsLike; +}): Promise { const { buildOptions } = params; const [themeName, ...themeVariantNames] = buildOptions.themeNames; diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts index 814fdb7b..3f38ac0a 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts @@ -24,7 +24,10 @@ import { bringInAccountV1 } from "./bringInAccountV1"; import { getThemeSrcDirPath } from "../../shared/getThemeSrcDirPath"; import { rmSync } from "../../tools/fs.rmSync"; import { readThisNpmPackageVersion } from "../../tools/readThisNpmPackageVersion"; -import { writeMetaInfKeycloakThemes, type MetaInfKeycloakTheme } from "../../shared/metaInfKeycloakThemes"; +import { + writeMetaInfKeycloakThemes, + type MetaInfKeycloakTheme +} from "../../shared/metaInfKeycloakThemes"; import { objectEntries } from "tsafe/objectEntries"; export type BuildOptionsLike = { @@ -43,22 +46,35 @@ export type BuildOptionsLike = { assert(); -export async function generateSrcMainResourcesForMainTheme(params: { themeName: string; buildOptions: BuildOptionsLike }): Promise { +export async function generateSrcMainResourcesForMainTheme(params: { + themeName: string; + buildOptions: BuildOptionsLike; +}): Promise { const { themeName, buildOptions } = params; - const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath }); + const { themeSrcDirPath } = getThemeSrcDirPath({ + reactAppRootDirPath: buildOptions.reactAppRootDirPath + }); const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => { const { themeType } = params; - return pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", themeName, themeType); + return pathJoin( + buildOptions.keycloakifyBuildDirPath, + "src", + "main", + "resources", + "theme", + themeName, + themeType + ); }; const cssGlobalsToDefine: Record = {}; const implementedThemeTypes: Record = { - "login": false, - "account": false, - "email": false + login: false, + account: false, + email: false }; for (const themeType of ["login", "account"] as const) { @@ -71,18 +87,22 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: const themeTypeDirPath = getThemeTypeDirPath({ themeType }); apply_replacers_and_move_to_theme_resources: { - const destDirPath = pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir); + 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 }); + rmSync(destDirPath, { recursive: true, force: true }); if (themeType === "account" && implementedThemeTypes.login) { // NOTE: We prevent doing it twice, it has been done for the login theme. transformCodebase({ - "srcDirPath": pathJoin( + srcDirPath: pathJoin( getThemeTypeDirPath({ - "themeType": "login" + themeType: "login" }), "resources", basenameOfTheKeycloakifyResourcesDir @@ -94,14 +114,17 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: } transformCodebase({ - "srcDirPath": buildOptions.reactAppBuildDirPath, + srcDirPath: buildOptions.reactAppBuildDirPath, destDirPath, - "transformSourceCode": ({ filePath, sourceCode }) => { + 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), + dirPath: pathJoin( + buildOptions.reactAppBuildDirPath, + keycloak_resources + ), filePath }) ) { @@ -109,39 +132,50 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: } if (/\.css?$/i.test(filePath)) { - const { cssGlobalsToDefine: cssGlobalsToDefineForThisFile, fixedCssCode } = replaceImportsInCssCode({ - "cssCode": sourceCode.toString("utf8") + const { + cssGlobalsToDefine: cssGlobalsToDefineForThisFile, + fixedCssCode + } = replaceImportsInCssCode({ + cssCode: sourceCode.toString("utf8") }); - Object.entries(cssGlobalsToDefineForThisFile).forEach(([key, value]) => { - cssGlobalsToDefine[key] = value; - }); + Object.entries(cssGlobalsToDefineForThisFile).forEach( + ([key, value]) => { + cssGlobalsToDefine[key] = value; + } + ); - return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") }; + return { + modifiedSourceCode: Buffer.from(fixedCssCode, "utf8") + }; } if (/\.js?$/i.test(filePath)) { const { fixedJsCode } = replaceImportsInJsCode({ - "jsCode": sourceCode.toString("utf8"), + jsCode: sourceCode.toString("utf8"), buildOptions }); - return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") }; + return { + modifiedSourceCode: Buffer.from(fixedJsCode, "utf8") + }; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); } const { generateFtlFilesCode } = generateFtlFilesCodeFactory({ themeName, - "indexHtmlCode": fs.readFileSync(pathJoin(buildOptions.reactAppBuildDirPath, "index.html")).toString("utf8"), + indexHtmlCode: fs + .readFileSync(pathJoin(buildOptions.reactAppBuildDirPath, "index.html")) + .toString("utf8"), cssGlobalsToDefine, buildOptions, - "keycloakifyVersion": readThisNpmPackageVersion(), + keycloakifyVersion: readThisNpmPackageVersion(), themeType, - "fieldNames": readFieldNameUsage({ + fieldNames: readFieldNameUsage({ themeSrcDirPath, themeType }) @@ -163,9 +197,12 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: ].forEach(pageId => { const { ftlCode } = generateFtlFilesCode({ pageId }); - fs.mkdirSync(themeTypeDirPath, { "recursive": true }); + fs.mkdirSync(themeTypeDirPath, { recursive: true }); - fs.writeFileSync(pathJoin(themeTypeDirPath, pageId), Buffer.from(ftlCode, "utf8")); + fs.writeFileSync( + pathJoin(themeTypeDirPath, pageId), + Buffer.from(ftlCode, "utf8") + ); }); generateMessageProperties({ @@ -174,15 +211,23 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: }).forEach(({ languageTag, propertiesFileSource }) => { const messagesDirPath = pathJoin(themeTypeDirPath, "messages"); - fs.mkdirSync(pathJoin(themeTypeDirPath, "messages"), { "recursive": true }); + fs.mkdirSync(pathJoin(themeTypeDirPath, "messages"), { + recursive: true + }); - const propertiesFilePath = pathJoin(messagesDirPath, `messages_${languageTag}.properties`); + const propertiesFilePath = pathJoin( + messagesDirPath, + `messages_${languageTag}.properties` + ); - fs.writeFileSync(propertiesFilePath, Buffer.from(propertiesFileSource, "utf8")); + fs.writeFileSync( + propertiesFilePath, + Buffer.from(propertiesFileSource, "utf8") + ); }); await downloadKeycloakStaticResources({ - "keycloakVersion": (() => { + keycloakVersion: (() => { switch (themeType) { case "account": return lastKeycloakVersionWithAccountV1; @@ -190,7 +235,7 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: return buildOptions.loginThemeResourcesFromKeycloakVersion; } })(), - "themeDirPath": pathResolve(pathJoin(themeTypeDirPath, "..")), + themeDirPath: pathResolve(pathJoin(themeTypeDirPath, "..")), themeType, buildOptions }); @@ -225,8 +270,8 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: implementedThemeTypes.email = true; transformCodebase({ - "srcDirPath": emailThemeSrcDirPath, - "destDirPath": getThemeTypeDirPath({ "themeType": "email" }) + srcDirPath: emailThemeSrcDirPath, + destDirPath: getThemeTypeDirPath({ themeType: "email" }) }); } @@ -237,24 +282,24 @@ export async function generateSrcMainResourcesForMainTheme(params: { themeName: } { - const metaInfKeycloakThemes: MetaInfKeycloakTheme = { "themes": [] }; + const metaInfKeycloakThemes: MetaInfKeycloakTheme = { themes: [] }; metaInfKeycloakThemes.themes.push({ - "name": themeName, - "types": objectEntries(implementedThemeTypes) + name: themeName, + types: objectEntries(implementedThemeTypes) .filter(([, isImplemented]) => isImplemented) .map(([themeType]) => themeType) }); if (implementedThemeTypes.account) { metaInfKeycloakThemes.themes.push({ - "name": accountV1ThemeName, - "types": ["account"] + name: accountV1ThemeName, + types: ["account"] }); } writeMetaInfKeycloakThemes({ - "keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath, + keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath, metaInfKeycloakThemes }); } diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts index 9dcd4012..519c6c69 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts @@ -1,7 +1,10 @@ import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path"; import { transformCodebase } from "../../tools/transformCodebase"; import type { BuildOptions } from "../../shared/buildOptions"; -import { readMetaInfKeycloakThemes, writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes"; +import { + readMetaInfKeycloakThemes, + writeMetaInfKeycloakThemes +} from "../../shared/metaInfKeycloakThemes"; import { assert } from "tsafe/assert"; export type BuildOptionsLike = { @@ -10,20 +13,37 @@ export type BuildOptionsLike = { assert(); -export function generateSrcMainResourcesForThemeVariant(params: { themeName: string; themeVariantName: string; buildOptions: BuildOptionsLike }) { +export function generateSrcMainResourcesForThemeVariant(params: { + themeName: string; + themeVariantName: string; + buildOptions: BuildOptionsLike; +}) { const { themeName, themeVariantName, buildOptions } = params; - const mainThemeDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", themeName); + const mainThemeDirPath = pathJoin( + buildOptions.keycloakifyBuildDirPath, + "src", + "main", + "resources", + "theme", + themeName + ); transformCodebase({ - "srcDirPath": mainThemeDirPath, - "destDirPath": pathJoin(mainThemeDirPath, "..", themeVariantName), - "transformSourceCode": ({ fileRelativePath, sourceCode }) => { - if (pathExtname(fileRelativePath) === ".ftl" && fileRelativePath.split(pathSep).length === 2) { + 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}";`), + .replace( + `out["themeName"] = "${themeName}";`, + `out["themeName"] = "${themeVariantName}";` + ), "utf8" ); @@ -32,25 +52,29 @@ export function generateSrcMainResourcesForThemeVariant(params: { themeName: str return { modifiedSourceCode }; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); { - const updatedMetaInfKeycloakThemes = readMetaInfKeycloakThemes({ "keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath }); + const updatedMetaInfKeycloakThemes = readMetaInfKeycloakThemes({ + keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath + }); updatedMetaInfKeycloakThemes.themes.push({ - "name": themeVariantName, - "types": (() => { - const theme = updatedMetaInfKeycloakThemes.themes.find(({ name }) => name === themeName); + name: themeVariantName, + types: (() => { + const theme = updatedMetaInfKeycloakThemes.themes.find( + ({ name }) => name === themeName + ); assert(theme !== undefined); return theme.types; })() }); writeMetaInfKeycloakThemes({ - "keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath, - "metaInfKeycloakThemes": updatedMetaInfKeycloakThemes + keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath, + metaInfKeycloakThemes: updatedMetaInfKeycloakThemes }); } } diff --git a/src/bin/keycloakify/generateSrcMainResources/readExtraPageNames.ts b/src/bin/keycloakify/generateSrcMainResources/readExtraPageNames.ts index c4237bfd..5d20305b 100644 --- a/src/bin/keycloakify/generateSrcMainResources/readExtraPageNames.ts +++ b/src/bin/keycloakify/generateSrcMainResources/readExtraPageNames.ts @@ -3,17 +3,26 @@ import { id } from "tsafe/id"; import { removeDuplicates } from "evt/tools/reducers/removeDuplicates"; import * as fs from "fs"; import { join as pathJoin } from "path"; -import { type ThemeType, accountThemePageIds, loginThemePageIds } from "../../shared/constants"; +import { + type ThemeType, + accountThemePageIds, + loginThemePageIds +} from "../../shared/constants"; -export function readExtraPagesNames(params: { themeSrcDirPath: string; themeType: ThemeType }): string[] { +export function readExtraPagesNames(params: { + themeSrcDirPath: string; + themeType: ThemeType; +}): string[] { const { themeSrcDirPath, themeType } = params; const filePaths = crawl({ - "dirPath": pathJoin(themeSrcDirPath, themeType), - "returnedPathsType": "absolute" + dirPath: pathJoin(themeSrcDirPath, themeType), + returnedPathsType: "absolute" }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath)); - const candidateFilePaths = filePaths.filter(filePath => /kcContext\.[^.]+$/.test(filePath)); + const candidateFilePaths = filePaths.filter(filePath => + /kcContext\.[^.]+$/.test(filePath) + ); if (candidateFilePaths.length === 0) { candidateFilePaths.push(...filePaths); @@ -24,7 +33,12 @@ export function readExtraPagesNames(params: { themeSrcDirPath: string; themeType for (const candidateFilPath of candidateFilePaths) { const rawSourceFile = fs.readFileSync(candidateFilPath).toString("utf8"); - extraPages.push(...Array.from(rawSourceFile.matchAll(/["']?pageId["']?\s*:\s*["']([^.]+.ftl)["']/g), m => m[1])); + extraPages.push( + ...Array.from( + rawSourceFile.matchAll(/["']?pageId["']?\s*:\s*["']([^.]+.ftl)["']/g), + m => m[1] + ) + ); } return extraPages.reduce(...removeDuplicates()).filter(pageId => { diff --git a/src/bin/keycloakify/generateSrcMainResources/readFieldNameUsage.ts b/src/bin/keycloakify/generateSrcMainResources/readFieldNameUsage.ts index 72a7a9a0..8efac289 100644 --- a/src/bin/keycloakify/generateSrcMainResources/readFieldNameUsage.ts +++ b/src/bin/keycloakify/generateSrcMainResources/readFieldNameUsage.ts @@ -5,13 +5,22 @@ import type { ThemeType } from "../../shared/constants"; import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath"; /** Assumes the theme type exists */ -export function readFieldNameUsage(params: { themeSrcDirPath: string; themeType: ThemeType }): string[] { +export function readFieldNameUsage(params: { + themeSrcDirPath: string; + themeType: ThemeType; +}): string[] { const { themeSrcDirPath, themeType } = params; const fieldNames = new Set(); - for (const srcDirPath of [pathJoin(getThisCodebaseRootDirPath(), "src", themeType), pathJoin(themeSrcDirPath, themeType)]) { - const filePaths = crawl({ "dirPath": srcDirPath, "returnedPathsType": "absolute" }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath)); + for (const srcDirPath of [ + pathJoin(getThisCodebaseRootDirPath(), "src", themeType), + pathJoin(themeSrcDirPath, themeType) + ]) { + const filePaths = crawl({ + dirPath: srcDirPath, + returnedPathsType: "absolute" + }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath)); for (const filePath of filePaths) { const rawSourceFile = fs.readFileSync(filePath).toString("utf8"); @@ -20,7 +29,13 @@ export function readFieldNameUsage(params: { themeSrcDirPath: string; themeType: continue; } - for (const functionName of ["printIfExists", "existsError", "get", "exists", "getFirstError"] as const) { + for (const functionName of [ + "printIfExists", + "existsError", + "get", + "exists", + "getFirstError" + ] as const) { if (!rawSourceFile.includes(functionName)) { continue; } @@ -40,9 +55,21 @@ export function readFieldNameUsage(params: { themeSrcDirPath: string; themeType: return part .split(",") .map(a => a.trim()) - .filter((...[, i]) => (functionName !== "printIfExists" ? true : i === 0)) - .filter(a => a.startsWith('"') || a.startsWith("'") || a.startsWith("`")) - .filter(a => a.endsWith('"') || a.endsWith("'") || a.endsWith("`")) + .filter((...[, i]) => + functionName !== "printIfExists" ? true : i === 0 + ) + .filter( + a => + a.startsWith('"') || + a.startsWith("'") || + a.startsWith("`") + ) + .filter( + a => + a.endsWith('"') || + a.endsWith("'") || + a.endsWith("`") + ) .map(a => a.slice(1).slice(0, -1)); }) .flat() diff --git a/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts b/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts index 151719f9..bf7f8ad0 100644 --- a/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +++ b/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts @@ -1,5 +1,9 @@ import * as fs from "fs"; -import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path"; +import { + join as pathJoin, + relative as pathRelative, + basename as pathBasename +} from "path"; import { assert } from "tsafe/assert"; import type { BuildOptions } from "../shared/buildOptions"; import { accountV1ThemeName } from "../shared/constants"; @@ -27,7 +31,10 @@ export function generateStartKeycloakTestingContainer(params: { const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme"); fs.writeFileSync( - pathJoin(buildOptions.keycloakifyBuildDirPath, generateStartKeycloakTestingContainer.basename), + pathJoin( + buildOptions.keycloakifyBuildDirPath, + generateStartKeycloakTestingContainer.basename + ), Buffer.from( [ "#!/usr/bin/env bash", @@ -45,9 +52,16 @@ export function generateStartKeycloakTestingContainer(params: { "$(pwd)", pathRelative(buildOptions.keycloakifyBuildDirPath, jarFilePath) )}":"/opt/keycloak/providers/${pathBasename(jarFilePath)}" \\`, - [...(doesImplementAccountTheme ? [accountV1ThemeName] : []), ...buildOptions.themeNames].map( + [ + ...(doesImplementAccountTheme ? [accountV1ThemeName] : []), + ...buildOptions.themeNames + ].map( themeName => - ` -v "${pathJoin("$(pwd)", themeRelativeDirPath, themeName).replace(/\\/g, "/")}":"/opt/keycloak/themes/${themeName}":rw \\` + ` -v "${pathJoin( + "$(pwd)", + themeRelativeDirPath, + themeName + ).replace(/\\/g, "/")}":"/opt/keycloak/themes/${themeName}":rw \\` ), ` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`, ` start-dev`, @@ -55,6 +69,6 @@ export function generateStartKeycloakTestingContainer(params: { ].join("\n"), "utf8" ), - { "mode": 0o755 } + { mode: 0o755 } ); } diff --git a/src/bin/keycloakify/keycloakify.ts b/src/bin/keycloakify/keycloakify.ts index ac4107e9..524d71cd 100644 --- a/src/bin/keycloakify/keycloakify.ts +++ b/src/bin/keycloakify/keycloakify.ts @@ -15,7 +15,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) let commandOutput: Buffer | undefined = undefined; try { - commandOutput = child_process.execSync("mvn --version", { "stdio": ["ignore", "pipe", "ignore"] }); + commandOutput = child_process.execSync("mvn --version", { + stdio: ["ignore", "pipe", "ignore"] + }); } catch {} if (commandOutput?.toString("utf8").includes("Apache Maven")) { @@ -34,7 +36,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } })(); - console.log(`${chalk.red("Apache Maven required.")} Install it with \`${chalk.bold(installationCommand)}\` (for example)`); + console.log( + `${chalk.red("Apache Maven required.")} Install it with \`${chalk.bold( + installationCommand + )}\` (for example)` + ); process.exit(1); } @@ -46,7 +52,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) console.log( [ chalk.cyan(`keycloakify v${readThisNpmPackageVersion()}`), - chalk.green(`Building the keycloak theme in .${pathSep}${pathRelative(process.cwd(), buildOptions.keycloakifyBuildDirPath)} ...`) + chalk.green( + `Building the keycloak theme in .${pathSep}${pathRelative( + process.cwd(), + buildOptions.keycloakifyBuildDirPath + )} ...` + ) ].join(" ") ); @@ -54,10 +65,15 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) { if (!fs.existsSync(buildOptions.keycloakifyBuildDirPath)) { - fs.mkdirSync(buildOptions.keycloakifyBuildDirPath, { "recursive": true }); + fs.mkdirSync(buildOptions.keycloakifyBuildDirPath, { + recursive: true + }); } - fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8")); + fs.writeFileSync( + pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), + Buffer.from("*", "utf8") + ); } await generateSrcMainResources({ buildOptions }); @@ -68,10 +84,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } child_process.execSync("npx vite", { - "cwd": buildOptions.reactAppRootDirPath, - "env": { + cwd: buildOptions.reactAppRootDirPath, + env: { ...process.env, - [vitePluginSubScriptEnvNames.runPostBuildScript]: JSON.stringify(buildOptions) + [vitePluginSubScriptEnvNames.runPostBuildScript]: + JSON.stringify(buildOptions) } }); } @@ -84,5 +101,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) await buildJars({ buildOptions }); } - console.log(chalk.green(`✓ built in ${((Date.now() - startTime) / 1000).toFixed(2)}s`)); + console.log( + chalk.green(`✓ built in ${((Date.now() - startTime) / 1000).toFixed(2)}s`) + ); } diff --git a/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts b/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts index 15e89eb2..780b81ae 100644 --- a/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +++ b/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts @@ -18,7 +18,15 @@ export function replaceImportsInCssCode(params: { cssCode: string }): { const cssGlobalsToDefine: Record = {}; new Set(cssCode.match(/url\(["']?\/[^/][^)"']+["']?\)[^;}]*?/g) ?? []).forEach( - match => (cssGlobalsToDefine["url" + crypto.createHash("sha256").update(match).digest("hex").substring(0, 15)] = match) + match => + (cssGlobalsToDefine[ + "url" + + crypto + .createHash("sha256") + .update(match) + .digest("hex") + .substring(0, 15) + ] = match) ); let fixedCssCode = cssCode; @@ -26,26 +34,37 @@ export function replaceImportsInCssCode(params: { cssCode: string }): { Object.keys(cssGlobalsToDefine).forEach( cssVariableName => //NOTE: split/join pattern ~ replace all - (fixedCssCode = fixedCssCode.split(cssGlobalsToDefine[cssVariableName]).join(`var(--${cssVariableName})`)) + (fixedCssCode = fixedCssCode + .split(cssGlobalsToDefine[cssVariableName]) + .join(`var(--${cssVariableName})`)) ); return { fixedCssCode, cssGlobalsToDefine }; } -export function generateCssCodeToDefineGlobals(params: { cssGlobalsToDefine: Record; buildOptions: BuildOptionsLike }): { +export function generateCssCodeToDefineGlobals(params: { + cssGlobalsToDefine: Record; + buildOptions: BuildOptionsLike; +}): { cssCodeToPrependInHead: string; } { const { cssGlobalsToDefine, buildOptions } = params; return { - "cssCodeToPrependInHead": [ + cssCodeToPrependInHead: [ ":root {", ...Object.keys(cssGlobalsToDefine) .map(cssVariableName => [ `--${cssVariableName}:`, cssGlobalsToDefine[cssVariableName].replace( - new RegExp(`url\\(${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`, "g"), + new RegExp( + `url\\(${(buildOptions.urlPathname ?? "/").replace( + /\//g, + "\\/" + )}`, + "g" + ), `url(\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/` ) ].join(" ") diff --git a/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts b/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts index 5ab068cd..f7d7ddb0 100644 --- a/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts +++ b/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts @@ -8,7 +8,10 @@ export type BuildOptionsLike = { assert(); -export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOptions: BuildOptionsLike }): { +export function replaceImportsInInlineCssCode(params: { + cssCode: string; + buildOptions: BuildOptionsLike; +}): { fixedCssCode: string; } { const { cssCode, buildOptions } = params; @@ -17,7 +20,8 @@ export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOp buildOptions.urlPathname === undefined ? /url\(["']?\/([^/][^)"']+)["']?\)/g : new RegExp(`url\\(["']?${buildOptions.urlPathname}([^)"']+)["']?\\)`, "g"), - (...[, group]) => `url(\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/${group})` + (...[, group]) => + `url(\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/${group})` ); return { fixedCssCode }; diff --git a/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts b/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts index 4327a737..bfff6d76 100644 --- a/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts +++ b/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts @@ -13,7 +13,10 @@ export type BuildOptionsLike = { assert(); -export function replaceImportsInJsCode(params: { jsCode: string; buildOptions: BuildOptionsLike }) { +export function replaceImportsInJsCode(params: { + jsCode: string; + buildOptions: BuildOptionsLike; +}) { const { jsCode, buildOptions } = params; const { fixedJsCode } = (() => { @@ -22,8 +25,8 @@ export function replaceImportsInJsCode(params: { jsCode: string; buildOptions: B return replaceImportsInJsCode_vite({ jsCode, buildOptions, - "basenameOfAssetsFiles": readAssetsDirSync({ - "assetsDirPath": params.buildOptions.assetsDirPath + basenameOfAssetsFiles: readAssetsDirSync({ + assetsDirPath: params.buildOptions.assetsDirPath }) }); case "webpack": diff --git a/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts b/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts index 8fb7ff8f..e55a6bdb 100644 --- a/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts +++ b/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts @@ -1,4 +1,7 @@ -import { nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../../shared/constants"; +import { + nameOfTheGlobal, + basenameOfTheKeycloakifyResourcesDir +} from "../../../shared/constants"; import { assert } from "tsafe/assert"; import type { BuildOptions } from "../../../shared/buildOptions"; import * as nodePath from "path"; @@ -20,7 +23,12 @@ export function replaceImportsInJsCode_vite(params: { }): { fixedJsCode: string; } { - const { jsCode, buildOptions, basenameOfAssetsFiles, systemType = nodePath.sep === "/" ? "posix" : "win32" } = params; + const { + jsCode, + buildOptions, + basenameOfAssetsFiles, + systemType = nodePath.sep === "/" ? "posix" : "win32" + } = params; const { relative: pathRelative, sep: pathSep } = nodePath[systemType]; @@ -38,22 +46,32 @@ export function replaceImportsInJsCode_vite(params: { // Replace `Hv=function(e){return"/abcde12345/"+e}` by `Hv=function(e){return"/"+e}` fixedJsCode = fixedJsCode.replace( new RegExp( - `([\\w\\$][\\w\\d\\$]*)=function\\(([\\w\\$][\\w\\d\\$]*)\\)\\{return"${replaceAll(buildOptions.urlPathname, "/", "\\/")}"\\+\\2\\}`, + `([\\w\\$][\\w\\d\\$]*)=function\\(([\\w\\$][\\w\\d\\$]*)\\)\\{return"${replaceAll( + buildOptions.urlPathname, + "/", + "\\/" + )}"\\+\\2\\}`, "g" ), - (...[, funcName, paramName]) => `${funcName}=function(${paramName}){return"/"+${paramName}}` + (...[, funcName, paramName]) => + `${funcName}=function(${paramName}){return"/"+${paramName}}` ); } replace_javascript_relatives_import_paths: { // Example: "assets/ or "foo/bar/" const staticDir = (() => { - let out = pathRelative(buildOptions.reactAppBuildDirPath, buildOptions.assetsDirPath); + let out = pathRelative( + buildOptions.reactAppBuildDirPath, + buildOptions.assetsDirPath + ); out = replaceAll(out, pathSep, "/") + "/"; if (out === "/") { - throw new Error(`The assetsDirPath must be a subdirectory of reactAppBuildDirPath`); + throw new Error( + `The assetsDirPath must be a subdirectory of reactAppBuildDirPath` + ); } return out; diff --git a/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts b/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts index 35154c39..5a334c75 100644 --- a/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts +++ b/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts @@ -1,4 +1,7 @@ -import { nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../../shared/constants"; +import { + nameOfTheGlobal, + basenameOfTheKeycloakifyResourcesDir +} from "../../../shared/constants"; import { assert } from "tsafe/assert"; import type { BuildOptions } from "../../../shared/buildOptions"; import * as nodePath from "path"; @@ -12,10 +15,18 @@ export type BuildOptionsLike = { assert(); -export function replaceImportsInJsCode_webpack(params: { jsCode: string; buildOptions: BuildOptionsLike; systemType?: "posix" | "win32" }): { +export function replaceImportsInJsCode_webpack(params: { + jsCode: string; + buildOptions: BuildOptionsLike; + systemType?: "posix" | "win32"; +}): { fixedJsCode: string; } { - const { jsCode, buildOptions, systemType = nodePath.sep === "/" ? "posix" : "win32" } = params; + const { + jsCode, + buildOptions, + systemType = nodePath.sep === "/" ? "posix" : "win32" + } = params; const { relative: pathRelative, sep: pathSep } = nodePath[systemType]; @@ -24,29 +35,51 @@ export function replaceImportsInJsCode_webpack(params: { jsCode: string; buildOp if (buildOptions.urlPathname !== undefined) { // "__esModule",{value:!0})},n.p="/foo-bar/",function(){if("undefined" -> ... n.p="/" ... fixedJsCode = fixedJsCode.replace( - new RegExp(`,([a-zA-Z]\\.[a-zA-Z])="${replaceAll(buildOptions.urlPathname, "/", "\\/")}",`, "g"), + new RegExp( + `,([a-zA-Z]\\.[a-zA-Z])="${replaceAll( + buildOptions.urlPathname, + "/", + "\\/" + )}",`, + "g" + ), (...[, assignTo]) => `,${assignTo}="/",` ); } // Example: "static/ or "foo/bar/" const staticDir = (() => { - let out = pathRelative(buildOptions.reactAppBuildDirPath, buildOptions.assetsDirPath); + let out = pathRelative( + buildOptions.reactAppBuildDirPath, + buildOptions.assetsDirPath + ); out = replaceAll(out, pathSep, "/") + "/"; if (out === "/") { - throw new Error(`The assetsDirPath must be a subdirectory of reactAppBuildDirPath`); + throw new Error( + `The assetsDirPath must be a subdirectory of reactAppBuildDirPath` + ); } return out; })(); - const getReplaceArgs = (language: "js" | "css"): Parameters => [ - new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=(function\\(([a-z]+)\\){return|([a-z]+)=>)"${staticDir.replace(/\//g, "\\/")}${language}\\/"`, "g"), + const getReplaceArgs = ( + language: "js" | "css" + ): Parameters => [ + new RegExp( + `([a-zA-Z_]+)\\.([a-zA-Z]+)=(function\\(([a-z]+)\\){return|([a-z]+)=>)"${staticDir.replace( + /\//g, + "\\/" + )}${language}\\/"`, + "g" + ), (...[, n, u, matchedFunction, eForFunction]) => { const isArrowFunction = matchedFunction.includes("=>"); - const e = isArrowFunction ? matchedFunction.replace("=>", "").trim() : eForFunction; + const e = isArrowFunction + ? matchedFunction.replace("=>", "").trim() + : eForFunction; return ` ${n}[(function(){ @@ -58,7 +91,9 @@ export function replaceImportsInJsCode_webpack(params: { jsCode: string; buildOp }); } return "${u}"; - })()] = ${isArrowFunction ? `${e} =>` : `function(${e}) { return `} "/${basenameOfTheKeycloakifyResourcesDir}/${staticDir}${language}/"` + })()] = ${ + isArrowFunction ? `${e} =>` : `function(${e}) { return ` + } "/${basenameOfTheKeycloakifyResourcesDir}/${staticDir}${language}/"` .replace(/\s+/g, " ") .trim(); } @@ -68,7 +103,10 @@ export function replaceImportsInJsCode_webpack(params: { jsCode: string; buildOp .replace(...getReplaceArgs("js")) .replace(...getReplaceArgs("css")) .replace( - new RegExp(`[a-zA-Z]+\\.[a-zA-Z]+\\+"${staticDir.replace(/\//g, "\\/")}`, "g"), + new RegExp( + `[a-zA-Z]+\\.[a-zA-Z]+\\+"${staticDir.replace(/\//g, "\\/")}`, + "g" + ), `window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/${staticDir}` ); diff --git a/src/bin/main.ts b/src/bin/main.ts index b53efcde..13589ff7 100644 --- a/src/bin/main.ts +++ b/src/bin/main.ts @@ -10,12 +10,12 @@ export type CliCommandOptions = { const program = termost( { - "name": "keycloakify", - "description": "Keycloakify CLI", - "version": readThisNpmPackageVersion() + name: "keycloakify", + description: "Keycloakify CLI", + version: readThisNpmPackageVersion() }, { - "onException": error => { + onException: error => { console.error(error); process.exit(1); } @@ -25,8 +25,8 @@ const program = termost( const optionsKeys: string[] = []; program.option({ - "key": "reactAppRootDirPath", - "name": (() => { + key: "reactAppRootDirPath", + name: (() => { const long = "project"; const short = "p"; @@ -34,19 +34,25 @@ program.option({ return { long, short }; })(), - "description": [ + description: [ `For monorepos, path to the keycloakify project.`, "Example: `npx keycloakify build --project packages/keycloak-theme`", "https://docs.keycloakify.dev/build-options#project-or-p-cli-option" ].join(" "), - "defaultValue": undefined + defaultValue: undefined }); function skip(_context: any, argv: { options: Record }) { - const unrecognizedOptionKey = Object.keys(argv.options).find(key => !optionsKeys.includes(key)); + const unrecognizedOptionKey = Object.keys(argv.options).find( + key => !optionsKeys.includes(key) + ); if (unrecognizedOptionKey !== undefined) { - console.error(`keycloakify: Unrecognized option: ${unrecognizedOptionKey.length === 1 ? "-" : "--"}${unrecognizedOptionKey}`); + console.error( + `keycloakify: Unrecognized option: ${ + unrecognizedOptionKey.length === 1 ? "-" : "--" + }${unrecognizedOptionKey}` + ); process.exit(1); } @@ -55,12 +61,12 @@ function skip(_context: any, argv: { options: Record }) { program .command({ - "name": "build", - "description": "Build the theme (default subcommand)." + name: "build", + description: "Build the theme (default subcommand)." }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./keycloakify"); await command({ cliCommandOptions }); @@ -73,48 +79,55 @@ program keycloakVersion: string | undefined; realmJsonFilePath: string | undefined; }>({ - "name": "start-keycloak", - "description": "Spin up a pre configured Docker image of Keycloak to test your theme." + name: "start-keycloak", + description: + "Spin up a pre configured Docker image of Keycloak to test your theme." }) .option({ - "key": "port", - "name": (() => { + key: "port", + name: (() => { const name = "port"; optionsKeys.push(name); return name; })(), - "description": ["Keycloak server port.", "Example `--port 8085`"].join(" "), - "defaultValue": 8080 + description: ["Keycloak server port.", "Example `--port 8085`"].join(" "), + defaultValue: 8080 }) .option({ - "key": "keycloakVersion", - "name": (() => { + key: "keycloakVersion", + name: (() => { const name = "keycloak-version"; optionsKeys.push(name); return name; })(), - "description": ["Use a specific version of Keycloak.", "Example `--keycloak-version 21.1.1`"].join(" "), - "defaultValue": undefined + description: [ + "Use a specific version of Keycloak.", + "Example `--keycloak-version 21.1.1`" + ].join(" "), + defaultValue: undefined }) .option({ - "key": "realmJsonFilePath", - "name": (() => { + key: "realmJsonFilePath", + name: (() => { const name = "import"; optionsKeys.push(name); return name; })(), - "defaultValue": undefined, - "description": ["Import your own realm configuration file", "Example `--import path/to/myrealm-realm.json`"].join(" ") + defaultValue: undefined, + description: [ + "Import your own realm configuration file", + "Example `--import path/to/myrealm-realm.json`" + ].join(" ") }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./start-keycloak"); await command({ cliCommandOptions }); @@ -123,12 +136,12 @@ program program .command({ - "name": "download-keycloak-default-theme", - "description": "Download the built-in Keycloak theme." + name: "download-keycloak-default-theme", + description: "Download the built-in Keycloak theme." }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./download-keycloak-default-theme"); await command({ cliCommandOptions }); @@ -137,12 +150,12 @@ program program .command({ - "name": "eject-page", - "description": "Eject a Keycloak page." + name: "eject-page", + description: "Eject a Keycloak page." }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./eject-page"); await command({ cliCommandOptions }); @@ -151,12 +164,12 @@ program program .command({ - "name": "initialize-email-theme", - "description": "Initialize an email theme." + name: "initialize-email-theme", + description: "Initialize an email theme." }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./initialize-email-theme"); await command({ cliCommandOptions }); @@ -165,12 +178,13 @@ program program .command({ - "name": "copy-keycloak-resources-to-public", - "description": "(Webpack/Create-React-App only) Copy Keycloak default theme resources to the public directory." + name: "copy-keycloak-resources-to-public", + description: + "(Webpack/Create-React-App only) Copy Keycloak default theme resources to the public directory." }) .task({ skip, - "handler": async cliCommandOptions => { + handler: async cliCommandOptions => { const { command } = await import("./copy-keycloak-resources-to-public"); await command({ cliCommandOptions }); @@ -181,10 +195,17 @@ program { const [, , ...rest] = process.argv; - if (rest.length === 0 || (rest[0].startsWith("-") && rest[0] !== "--help" && rest[0] !== "-h")) { - const { status } = child_process.spawnSync("npx", ["keycloakify", "build", ...rest], { - "stdio": "inherit" - }); + if ( + rest.length === 0 || + (rest[0].startsWith("-") && rest[0] !== "--help" && rest[0] !== "-h") + ) { + const { status } = child_process.spawnSync( + "npx", + ["keycloakify", "build", ...rest], + { + stdio: "inherit" + } + ); process.exit(status ?? 1); } diff --git a/src/bin/shared/KeycloakVersionRange.ts b/src/bin/shared/KeycloakVersionRange.ts index 43921953..48d286fe 100644 --- a/src/bin/shared/KeycloakVersionRange.ts +++ b/src/bin/shared/KeycloakVersionRange.ts @@ -1,4 +1,6 @@ -export type KeycloakVersionRange = KeycloakVersionRange.WithAccountTheme | KeycloakVersionRange.WithoutAccountTheme; +export type KeycloakVersionRange = + | KeycloakVersionRange.WithAccountTheme + | KeycloakVersionRange.WithoutAccountTheme; export namespace KeycloakVersionRange { export type WithoutAccountTheme = "21-and-below" | "22-and-above"; diff --git a/src/bin/shared/buildOptions.ts b/src/bin/shared/buildOptions.ts index 5b545720..7d9d8a33 100644 --- a/src/bin/shared/buildOptions.ts +++ b/src/bin/shared/buildOptions.ts @@ -49,7 +49,9 @@ export type ResolvedViteConfig = { userProvidedBuildOptions: UserProvidedBuildOptions; }; -export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions }): BuildOptions { +export function readBuildOptions(params: { + cliCommandOptions: CliCommandOptions; +}): BuildOptions { const { cliCommandOptions } = params; const reactAppRootDirPath = (() => { @@ -58,29 +60,39 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions } return getAbsoluteAndInOsFormatPath({ - "pathIsh": cliCommandOptions.reactAppRootDirPath, - "cwd": process.cwd() + pathIsh: cliCommandOptions.reactAppRootDirPath, + cwd: process.cwd() }); })(); const { resolvedViteConfig } = (() => { - if (fs.readdirSync(reactAppRootDirPath).find(fileBasename => fileBasename.startsWith("vite.config")) === undefined) { - return { "resolvedViteConfig": undefined }; + if ( + fs + .readdirSync(reactAppRootDirPath) + .find(fileBasename => fileBasename.startsWith("vite.config")) === + undefined + ) { + return { resolvedViteConfig: undefined }; } const output = child_process .execSync("npx vite", { - "cwd": reactAppRootDirPath, - "env": { + cwd: reactAppRootDirPath, + env: { ...process.env, [vitePluginSubScriptEnvNames.resolveViteConfig]: "true" } }) .toString("utf8"); - assert(output.includes(vitePluginSubScriptEnvNames.resolveViteConfig), "Seems like the Keycloakify's Vite plugin is not installed."); + assert( + output.includes(vitePluginSubScriptEnvNames.resolveViteConfig), + "Seems like the Keycloakify's Vite plugin is not installed." + ); - const resolvedViteConfigStr = output.split(vitePluginSubScriptEnvNames.resolveViteConfig).reverse()[0]; + const resolvedViteConfigStr = output + .split(vitePluginSubScriptEnvNames.resolveViteConfig) + .reverse()[0]; const resolvedViteConfig: ResolvedViteConfig = JSON.parse(resolvedViteConfigStr); @@ -92,22 +104,24 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions name: string; version?: string; homepage?: string; - keycloakify?: UserProvidedBuildOptions & { reactAppBuildDirPath?: string }; + keycloakify?: UserProvidedBuildOptions & { + reactAppBuildDirPath?: string; + }; }; const zParsedPackageJson = z.object({ - "name": z.string(), - "version": z.string().optional(), - "homepage": z.string().optional(), - "keycloakify": z + name: z.string(), + version: z.string().optional(), + homepage: z.string().optional(), + keycloakify: z .object({ - "extraThemeProperties": z.array(z.string()).optional(), - "artifactId": z.string().optional(), - "groupId": z.string().optional(), - "loginThemeResourcesFromKeycloakVersion": z.string().optional(), - "reactAppBuildDirPath": z.string().optional(), - "keycloakifyBuildDirPath": z.string().optional(), - "themeName": z.union([z.string(), z.array(z.string())]).optional() + extraThemeProperties: z.array(z.string()).optional(), + artifactId: z.string().optional(), + groupId: z.string().optional(), + loginThemeResourcesFromKeycloakVersion: z.string().optional(), + reactAppBuildDirPath: z.string().optional(), + keycloakifyBuildDirPath: z.string().optional(), + themeName: z.union([z.string(), z.array(z.string())]).optional() }) .optional() }); @@ -119,7 +133,13 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions assert(); } - return zParsedPackageJson.parse(JSON.parse(fs.readFileSync(pathJoin(reactAppRootDirPath, "package.json")).toString("utf8"))); + return zParsedPackageJson.parse( + JSON.parse( + fs + .readFileSync(pathJoin(reactAppRootDirPath, "package.json")) + .toString("utf8") + ) + ); })(); const userProvidedBuildOptions: UserProvidedBuildOptions = { @@ -152,8 +172,8 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions if (parsedPackageJson.keycloakify?.reactAppBuildDirPath !== undefined) { return getAbsoluteAndInOsFormatPath({ - "pathIsh": parsedPackageJson.keycloakify.reactAppBuildDirPath, - "cwd": reactAppRootDirPath + pathIsh: parsedPackageJson.keycloakify.reactAppBuildDirPath, + cwd: reactAppRootDirPath }); } @@ -165,15 +185,16 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions const { npmWorkspaceRootDirPath } = getNpmWorkspaceRootDirPath({ reactAppRootDirPath, - "dependencyExpected": "keycloakify" + dependencyExpected: "keycloakify" }); return { - "bundler": resolvedViteConfig !== undefined ? "vite" : "webpack", - "themeVersion": process.env.KEYCLOAKIFY_THEME_VERSION ?? parsedPackageJson.version ?? "0.0.0", + bundler: resolvedViteConfig !== undefined ? "vite" : "webpack", + themeVersion: + process.env.KEYCLOAKIFY_THEME_VERSION ?? parsedPackageJson.version ?? "0.0.0", themeNames, - "extraThemeProperties": userProvidedBuildOptions.extraThemeProperties, - "groupId": (() => { + extraThemeProperties: userProvidedBuildOptions.extraThemeProperties, + groupId: (() => { const fallbackGroupId = `${themeNames[0]}.keycloak`; return ( @@ -188,24 +209,30 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions .join(".") ?? fallbackGroupId) + ".keycloak" ); })(), - "artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? userProvidedBuildOptions.artifactId ?? `${themeNames[0]}-keycloak-theme`, - "loginThemeResourcesFromKeycloakVersion": userProvidedBuildOptions.loginThemeResourcesFromKeycloakVersion ?? "24.0.4", + artifactId: + process.env.KEYCLOAKIFY_ARTIFACT_ID ?? + userProvidedBuildOptions.artifactId ?? + `${themeNames[0]}-keycloak-theme`, + loginThemeResourcesFromKeycloakVersion: + userProvidedBuildOptions.loginThemeResourcesFromKeycloakVersion ?? "24.0.4", reactAppRootDirPath, reactAppBuildDirPath, - "keycloakifyBuildDirPath": (() => { + keycloakifyBuildDirPath: (() => { if (userProvidedBuildOptions.keycloakifyBuildDirPath !== undefined) { return getAbsoluteAndInOsFormatPath({ - "pathIsh": userProvidedBuildOptions.keycloakifyBuildDirPath, - "cwd": reactAppRootDirPath + pathIsh: userProvidedBuildOptions.keycloakifyBuildDirPath, + cwd: reactAppRootDirPath }); } return pathJoin( reactAppRootDirPath, - resolvedViteConfig?.buildDir === undefined ? "build_keycloak" : `${resolvedViteConfig.buildDir}_keycloak` + resolvedViteConfig?.buildDir === undefined + ? "build_keycloak" + : `${resolvedViteConfig.buildDir}_keycloak` ); })(), - "publicDirPath": (() => { + publicDirPath: (() => { webpack: { if (resolvedViteConfig !== undefined) { break webpack; @@ -213,8 +240,8 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions if (process.env.PUBLIC_DIR_PATH !== undefined) { return getAbsoluteAndInOsFormatPath({ - "pathIsh": process.env.PUBLIC_DIR_PATH, - "cwd": reactAppRootDirPath + pathIsh: process.env.PUBLIC_DIR_PATH, + cwd: reactAppRootDirPath }); } @@ -223,13 +250,13 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions return pathJoin(reactAppRootDirPath, resolvedViteConfig.publicDir); })(), - "cacheDirPath": (() => { + cacheDirPath: (() => { const cacheDirPath = pathJoin( (() => { if (process.env.XDG_CACHE_HOME !== undefined) { return getAbsoluteAndInOsFormatPath({ - "pathIsh": process.env.XDG_CACHE_HOME, - "cwd": process.cwd() + pathIsh: process.env.XDG_CACHE_HOME, + cwd: process.cwd() }); } @@ -240,7 +267,7 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions return cacheDirPath; })(), - "urlPathname": (() => { + urlPathname: (() => { webpack: { if (resolvedViteConfig !== undefined) { break webpack; @@ -264,7 +291,7 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions return resolvedViteConfig.urlPathname; })(), - "assetsDirPath": (() => { + assetsDirPath: (() => { webpack: { if (resolvedViteConfig !== undefined) { break webpack; diff --git a/src/bin/shared/constants.ts b/src/bin/shared/constants.ts index 8663c083..ebd7bf3d 100644 --- a/src/bin/shared/constants.ts +++ b/src/bin/shared/constants.ts @@ -10,8 +10,8 @@ export const accountV1ThemeName = "account-v1"; export type ThemeType = (typeof themeTypes)[number]; export const vitePluginSubScriptEnvNames = { - "runPostBuildScript": "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT", - "resolveViteConfig": "KEYCLOAKIFY_RESOLVE_VITE_CONFIG" + runPostBuildScript: "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT", + resolveViteConfig: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG" } as const; export const skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR"; diff --git a/src/bin/shared/copyKeycloakResourcesToPublic.ts b/src/bin/shared/copyKeycloakResourcesToPublic.ts index 3cc33ac2..d94779c4 100644 --- a/src/bin/shared/copyKeycloakResourcesToPublic.ts +++ b/src/bin/shared/copyKeycloakResourcesToPublic.ts @@ -3,7 +3,11 @@ import { type BuildOptionsLike as BuildOptionsLike_downloadKeycloakStaticResources } from "./downloadKeycloakStaticResources"; import { join as pathJoin, relative as pathRelative } from "path"; -import { themeTypes, keycloak_resources, lastKeycloakVersionWithAccountV1 } from "../shared/constants"; +import { + themeTypes, + keycloak_resources, + lastKeycloakVersionWithAccountV1 +} from "../shared/constants"; import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion"; import { assert } from "tsafe/assert"; import * as fs from "fs"; @@ -17,7 +21,9 @@ export type BuildOptionsLike = BuildOptionsLike_downloadKeycloakStaticResources assert(); -export async function copyKeycloakResourcesToPublic(params: { buildOptions: BuildOptionsLike }) { +export async function copyKeycloakResourcesToPublic(params: { + buildOptions: BuildOptionsLike; +}) { const { buildOptions } = params; const destDirPath = pathJoin(buildOptions.publicDirPath, keycloak_resources); @@ -27,11 +33,14 @@ export async function copyKeycloakResourcesToPublic(params: { buildOptions: Buil const keycloakifyBuildinfoRaw = JSON.stringify( { destDirPath, - "keycloakifyVersion": readThisNpmPackageVersion(), - "buildOptions": { - "loginThemeResourcesFromKeycloakVersion": readThisNpmPackageVersion(), - "cacheDirPath": pathRelative(destDirPath, buildOptions.cacheDirPath), - "npmWorkspaceRootDirPath": pathRelative(destDirPath, buildOptions.npmWorkspaceRootDirPath) + keycloakifyVersion: readThisNpmPackageVersion(), + buildOptions: { + loginThemeResourcesFromKeycloakVersion: readThisNpmPackageVersion(), + cacheDirPath: pathRelative(destDirPath, buildOptions.cacheDirPath), + npmWorkspaceRootDirPath: pathRelative( + destDirPath, + buildOptions.npmWorkspaceRootDirPath + ) } }, null, @@ -43,7 +52,9 @@ export async function copyKeycloakResourcesToPublic(params: { buildOptions: Buil break skip_if_already_done; } - const keycloakifyBuildinfoRaw_previousRun = fs.readFileSync(keycloakifyBuildinfoFilePath).toString("utf8"); + const keycloakifyBuildinfoRaw_previousRun = fs + .readFileSync(keycloakifyBuildinfoFilePath) + .toString("utf8"); if (keycloakifyBuildinfoRaw_previousRun !== keycloakifyBuildinfoRaw) { break skip_if_already_done; @@ -52,15 +63,15 @@ export async function copyKeycloakResourcesToPublic(params: { buildOptions: Buil return; } - rmSync(destDirPath, { "force": true, "recursive": true }); + rmSync(destDirPath, { force: true, recursive: true }); - fs.mkdirSync(destDirPath, { "recursive": true }); + fs.mkdirSync(destDirPath, { recursive: true }); fs.writeFileSync(pathJoin(destDirPath, ".gitignore"), Buffer.from("*", "utf8")); for (const themeType of themeTypes) { await downloadKeycloakStaticResources({ - "keycloakVersion": (() => { + keycloakVersion: (() => { switch (themeType) { case "login": return buildOptions.loginThemeResourcesFromKeycloakVersion; @@ -69,7 +80,7 @@ export async function copyKeycloakResourcesToPublic(params: { buildOptions: Buil } })(), themeType, - "themeDirPath": destDirPath, + themeDirPath: destDirPath, buildOptions }); } @@ -86,5 +97,8 @@ export async function copyKeycloakResourcesToPublic(params: { buildOptions: Buil ) ); - fs.writeFileSync(keycloakifyBuildinfoFilePath, Buffer.from(keycloakifyBuildinfoRaw, "utf8")); + fs.writeFileSync( + keycloakifyBuildinfoFilePath, + Buffer.from(keycloakifyBuildinfoRaw, "utf8") + ); } diff --git a/src/bin/shared/downloadAndUnzip.ts b/src/bin/shared/downloadAndUnzip.ts index f39e1113..cc1a6ea3 100644 --- a/src/bin/shared/downloadAndUnzip.ts +++ b/src/bin/shared/downloadAndUnzip.ts @@ -28,22 +28,29 @@ export async function downloadAndUnzip(params: { }; buildOptions: BuildOptionsLike; }) { - const { url, destDirPath, specificDirsToExtract, preCacheTransform, buildOptions } = params; + const { url, destDirPath, specificDirsToExtract, preCacheTransform, buildOptions } = + params; const { extractDirPath, zipFilePath } = (() => { const zipFileBasenameWithoutExt = generateFileNameFromURL({ url, - "preCacheTransform": + preCacheTransform: preCacheTransform === undefined ? undefined : { - "actionCacheId": preCacheTransform.actionCacheId, - "actionFootprint": preCacheTransform.action.toString() + actionCacheId: preCacheTransform.actionCacheId, + actionFootprint: preCacheTransform.action.toString() } }); - const zipFilePath = pathJoin(buildOptions.cacheDirPath, `${zipFileBasenameWithoutExt}.zip`); - const extractDirPath = pathJoin(buildOptions.cacheDirPath, `tmp_unzip_${zipFileBasenameWithoutExt}`); + const zipFilePath = pathJoin( + buildOptions.cacheDirPath, + `${zipFileBasenameWithoutExt}.zip` + ); + const extractDirPath = pathJoin( + buildOptions.cacheDirPath, + `tmp_unzip_${zipFileBasenameWithoutExt}` + ); return { zipFilePath, extractDirPath }; })(); @@ -55,28 +62,30 @@ export async function downloadAndUnzip(params: { const { response, isFromRemoteCache } = await (async () => { const proxyFetchOptions = await getProxyFetchOptions({ - "npmWorkspaceRootDirPath": buildOptions.npmWorkspaceRootDirPath + npmWorkspaceRootDirPath: buildOptions.npmWorkspaceRootDirPath }); const response = await fetch( - `https://github.com/keycloakify/keycloakify/releases/download/v0.0.1/${pathBasename(zipFilePath)}`, + `https://github.com/keycloakify/keycloakify/releases/download/v0.0.1/${pathBasename( + zipFilePath + )}`, proxyFetchOptions ); if (response.status === 200) { return { response, - "isFromRemoteCache": true + isFromRemoteCache: true }; } return { - "response": await fetch(url, proxyFetchOptions), - "isFromRemoteCache": false + response: await fetch(url, proxyFetchOptions), + isFromRemoteCache: false }; })(); - await mkdir(pathDirname(zipFilePath), { "recursive": true }); + await mkdir(pathDirname(zipFilePath), { recursive: true }); /** * The correct way to fix this is to upgrade node-fetch beyond 3.2.5 @@ -102,10 +111,13 @@ export async function downloadAndUnzip(params: { try { await preCacheTransform?.action({ - "destDirPath": extractDirPath + destDirPath: extractDirPath }); } catch (error) { - await Promise.all([rm(extractDirPath, { "recursive": true }), unlink(zipFilePath)]); + await Promise.all([ + rm(extractDirPath, { recursive: true }), + unlink(zipFilePath) + ]); throw error; } @@ -114,10 +126,11 @@ export async function downloadAndUnzip(params: { await zip(extractDirPath, zipFilePath); - await rm(extractDirPath, { "recursive": true }); + await rm(extractDirPath, { recursive: true }); upload_to_remote_cache_if_admin: { - const githubToken = process.env["KEYCLOAKIFY_ADMIN_GITHUB_PERSONAL_ACCESS_TOKEN"]; + const githubToken = + process.env["KEYCLOAKIFY_ADMIN_GITHUB_PERSONAL_ACCESS_TOKEN"]; if (!githubToken) { break upload_to_remote_cache_if_admin; @@ -145,7 +158,9 @@ export async function downloadAndUnzip(params: { githubToken ]); } catch { - console.log("upload failed, asset probably already exists in remote cache"); + console.log( + "upload failed, asset probably already exists in remote cache" + ); } } } @@ -153,11 +168,11 @@ export async function downloadAndUnzip(params: { await unzip(zipFilePath, extractDirPath); transformCodebase({ - "srcDirPath": extractDirPath, - "destDirPath": destDirPath + srcDirPath: extractDirPath, + destDirPath: destDirPath }); - await rm(extractDirPath, { "recursive": true }); + await rm(extractDirPath, { recursive: true }); } function generateFileNameFromURL(params: { @@ -194,9 +209,15 @@ function generateFileNameFromURL(params: { } // Sanitize actionCacheId the same way as other components - const sanitizedActionCacheId = preCacheTransform.actionCacheId.replace(/[^a-zA-Z0-9-_]/g, "_"); + const sanitizedActionCacheId = preCacheTransform.actionCacheId.replace( + /[^a-zA-Z0-9-_]/g, + "_" + ); - fileName += `_${sanitizedActionCacheId}_${createHash("sha256").update(preCacheTransform.actionFootprint).digest("hex").substring(0, 5)}`; + fileName += `_${sanitizedActionCacheId}_${createHash("sha256") + .update(preCacheTransform.actionFootprint) + .digest("hex") + .substring(0, 5)}`; } return fileName; diff --git a/src/bin/shared/downloadKeycloakDefaultTheme.ts b/src/bin/shared/downloadKeycloakDefaultTheme.ts index 2d258146..04113fda 100644 --- a/src/bin/shared/downloadKeycloakDefaultTheme.ts +++ b/src/bin/shared/downloadKeycloakDefaultTheme.ts @@ -15,25 +15,38 @@ export type BuildOptionsLike = { assert(); -export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: string; destDirPath: string; buildOptions: BuildOptionsLike }) { +export async function downloadKeycloakDefaultTheme(params: { + keycloakVersion: string; + destDirPath: string; + buildOptions: BuildOptionsLike; +}) { const { keycloakVersion, destDirPath, buildOptions } = params; await downloadAndUnzip({ destDirPath, - "url": `https://github.com/keycloak/keycloak/archive/refs/tags/${keycloakVersion}.zip`, - "specificDirsToExtract": ["", "-community"].map(ext => `keycloak-${keycloakVersion}/themes/src/main/resources${ext}/theme`), + url: `https://github.com/keycloak/keycloak/archive/refs/tags/${keycloakVersion}.zip`, + specificDirsToExtract: ["", "-community"].map( + ext => `keycloak-${keycloakVersion}/themes/src/main/resources${ext}/theme` + ), buildOptions, - "preCacheTransform": { - "actionCacheId": "npm install and build", - "action": async ({ destDirPath }) => { + preCacheTransform: { + actionCacheId: "npm install and build", + action: async ({ destDirPath }) => { install_common_node_modules: { - const commonResourcesDirPath = pathJoin(destDirPath, "keycloak", "common", "resources"); + const commonResourcesDirPath = pathJoin( + destDirPath, + "keycloak", + "common", + "resources" + ); if (!fs.existsSync(commonResourcesDirPath)) { break install_common_node_modules; } - if (!fs.existsSync(pathJoin(commonResourcesDirPath, "package.json"))) { + if ( + !fs.existsSync(pathJoin(commonResourcesDirPath, "package.json")) + ) { break install_common_node_modules; } @@ -42,36 +55,67 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st } child_process.execSync("npm install --omit=dev", { - "cwd": commonResourcesDirPath, - "stdio": "ignore" + cwd: commonResourcesDirPath, + stdio: "ignore" }); } repatriate_common_resources_from_base_login_theme: { - const baseLoginThemeResourceDir = pathJoin(destDirPath, "base", "login", "resources"); + const baseLoginThemeResourceDir = pathJoin( + destDirPath, + "base", + "login", + "resources" + ); if (!fs.existsSync(baseLoginThemeResourceDir)) { break repatriate_common_resources_from_base_login_theme; } transformCodebase({ - "srcDirPath": baseLoginThemeResourceDir, - "destDirPath": pathJoin(destDirPath, "keycloak", "login", "resources") + srcDirPath: baseLoginThemeResourceDir, + destDirPath: pathJoin( + destDirPath, + "keycloak", + "login", + "resources" + ) }); } install_and_move_to_common_resources_generated_in_keycloak_v2: { - if (!fs.readFileSync(pathJoin(destDirPath, "keycloak", "login", "theme.properties")).toString("utf8").includes("web_modules")) { + if ( + !fs + .readFileSync( + pathJoin( + destDirPath, + "keycloak", + "login", + "theme.properties" + ) + ) + .toString("utf8") + .includes("web_modules") + ) { break install_and_move_to_common_resources_generated_in_keycloak_v2; } - const accountV2DirSrcDirPath = pathJoin(destDirPath, "keycloak.v2", "account", "src"); + const accountV2DirSrcDirPath = pathJoin( + destDirPath, + "keycloak.v2", + "account", + "src" + ); if (!fs.existsSync(accountV2DirSrcDirPath)) { break install_and_move_to_common_resources_generated_in_keycloak_v2; } - const packageManager = fs.existsSync(pathJoin(accountV2DirSrcDirPath, "pnpm-lock.yaml")) ? "pnpm" : "npm"; + const packageManager = fs.existsSync( + pathJoin(accountV2DirSrcDirPath, "pnpm-lock.yaml") + ) + ? "pnpm" + : "npm"; if (packageManager === "pnpm") { try { @@ -82,9 +126,15 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st } } - child_process.execSync(`${packageManager} install`, { "cwd": accountV2DirSrcDirPath, "stdio": "ignore" }); + child_process.execSync(`${packageManager} install`, { + cwd: accountV2DirSrcDirPath, + stdio: "ignore" + }); - const packageJsonFilePath = pathJoin(accountV2DirSrcDirPath, "package.json"); + const packageJsonFilePath = pathJoin( + accountV2DirSrcDirPath, + "package.json" + ); const packageJsonRaw = fs.readFileSync(packageJsonFilePath); @@ -94,13 +144,21 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st .replace(`${packageManager} run check-types`, "true") .replace(`${packageManager} run babel`, "true"); - fs.writeFileSync(packageJsonFilePath, Buffer.from(JSON.stringify(parsedPackageJson, null, 2), "utf8")); + fs.writeFileSync( + packageJsonFilePath, + Buffer.from(JSON.stringify(parsedPackageJson, null, 2), "utf8") + ); - child_process.execSync(`${packageManager} run build`, { "cwd": accountV2DirSrcDirPath, "stdio": "ignore" }); + child_process.execSync(`${packageManager} run build`, { + cwd: accountV2DirSrcDirPath, + stdio: "ignore" + }); fs.writeFileSync(packageJsonFilePath, packageJsonRaw); - fs.rmSync(pathJoin(accountV2DirSrcDirPath, "node_modules"), { "recursive": true }); + fs.rmSync(pathJoin(accountV2DirSrcDirPath, "node_modules"), { + recursive: true + }); } remove_keycloak_v2: { @@ -110,12 +168,18 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st break remove_keycloak_v2; } - rmSync(keycloakV2DirPath, { "recursive": true }); + rmSync(keycloakV2DirPath, { recursive: true }); } // Note, this is an optimization for reducing the size of the jar remove_unused_node_modules: { - const nodeModuleDirPath = pathJoin(destDirPath, "keycloak", "common", "resources", "node_modules"); + const nodeModuleDirPath = pathJoin( + destDirPath, + "keycloak", + "common", + "resources", + "node_modules" + ); if (!fs.existsSync(nodeModuleDirPath)) { break remove_unused_node_modules; @@ -167,18 +231,26 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st ]; transformCodebase({ - "srcDirPath": nodeModuleDirPath, - "destDirPath": nodeModuleDirPath, - "transformSourceCode": ({ sourceCode, fileRelativePath }) => { + srcDirPath: nodeModuleDirPath, + destDirPath: nodeModuleDirPath, + transformSourceCode: ({ sourceCode, fileRelativePath }) => { if (fileRelativePath.endsWith(".map")) { return undefined; } - if (toDeletePerfixes.find(prefix => fileRelativePath.startsWith(prefix)) !== undefined) { + if ( + toDeletePerfixes.find(prefix => + fileRelativePath.startsWith(prefix) + ) !== undefined + ) { return undefined; } - if (fileRelativePath.startsWith(pathJoin("patternfly", "dist", "fonts"))) { + if ( + fileRelativePath.startsWith( + pathJoin("patternfly", "dist", "fonts") + ) + ) { if ( !fileRelativePath.endsWith(".woff2") && !fileRelativePath.endsWith(".woff") && @@ -188,34 +260,50 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st } } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); } // Just like node_modules remove_unused_lib: { - const libDirPath = pathJoin(destDirPath, "keycloak", "common", "resources", "lib"); + const libDirPath = pathJoin( + destDirPath, + "keycloak", + "common", + "resources", + "lib" + ); if (!fs.existsSync(libDirPath)) { break remove_unused_lib; } - const toDeletePerfixes = ["ui-ace", "filesaver", "fileupload", "angular", "ui-ace"]; + const toDeletePerfixes = [ + "ui-ace", + "filesaver", + "fileupload", + "angular", + "ui-ace" + ]; transformCodebase({ - "srcDirPath": libDirPath, - "destDirPath": libDirPath, - "transformSourceCode": ({ sourceCode, fileRelativePath }) => { + srcDirPath: libDirPath, + destDirPath: libDirPath, + transformSourceCode: ({ sourceCode, fileRelativePath }) => { if (fileRelativePath.endsWith(".map")) { return undefined; } - if (toDeletePerfixes.find(prefix => fileRelativePath.startsWith(prefix)) !== undefined) { + if ( + toDeletePerfixes.find(prefix => + fileRelativePath.startsWith(prefix) + ) !== undefined + ) { return undefined; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); } @@ -226,34 +314,61 @@ export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: st } { - const accountCssFilePath = pathJoin(destDirPath, "keycloak", "account", "resources", "css", "account.css"); + const accountCssFilePath = pathJoin( + destDirPath, + "keycloak", + "account", + "resources", + "css", + "account.css" + ); fs.writeFileSync( accountCssFilePath, - Buffer.from(fs.readFileSync(accountCssFilePath).toString("utf8").replace("top: -34px;", "top: -34px !important;"), "utf8") + Buffer.from( + fs + .readFileSync(accountCssFilePath) + .toString("utf8") + .replace("top: -34px;", "top: -34px !important;"), + "utf8" + ) ); } // Note, this is an optimization for reducing the size of the jar, // For this version we know exactly which resources are used. { - const nodeModulesDirPath = pathJoin(destDirPath, "keycloak", "common", "resources", "node_modules"); + const nodeModulesDirPath = pathJoin( + destDirPath, + "keycloak", + "common", + "resources", + "node_modules" + ); const toKeepPrefixes = [ - ...["patternfly.min.css", "patternfly-additions.min.css", "patternfly-additions.min.css"].map(fileBasename => + ...[ + "patternfly.min.css", + "patternfly-additions.min.css", + "patternfly-additions.min.css" + ].map(fileBasename => pathJoin("patternfly", "dist", "css", fileBasename) ), pathJoin("patternfly", "dist", "fonts") ]; transformCodebase({ - "srcDirPath": nodeModulesDirPath, - "destDirPath": nodeModulesDirPath, - "transformSourceCode": ({ sourceCode, fileRelativePath }) => { - if (toKeepPrefixes.find(prefix => fileRelativePath.startsWith(prefix)) === undefined) { + srcDirPath: nodeModulesDirPath, + destDirPath: nodeModulesDirPath, + transformSourceCode: ({ sourceCode, fileRelativePath }) => { + if ( + toKeepPrefixes.find(prefix => + fileRelativePath.startsWith(prefix) + ) === undefined + ) { return undefined; } - return { "modifiedSourceCode": sourceCode }; + return { modifiedSourceCode: sourceCode }; } }); } diff --git a/src/bin/shared/downloadKeycloakStaticResources.ts b/src/bin/shared/downloadKeycloakStaticResources.ts index 024cbe99..4aa57f36 100644 --- a/src/bin/shared/downloadKeycloakStaticResources.ts +++ b/src/bin/shared/downloadKeycloakStaticResources.ts @@ -24,26 +24,30 @@ export async function downloadKeycloakStaticResources(params: { const tmpDirPath = pathJoin( buildOptions.cacheDirPath, - `downloadKeycloakStaticResources_tmp_${crypto.createHash("sha256").update(`${themeType}-${keycloakVersion}`).digest("hex").slice(0, 8)}` + `downloadKeycloakStaticResources_tmp_${crypto + .createHash("sha256") + .update(`${themeType}-${keycloakVersion}`) + .digest("hex") + .slice(0, 8)}` ); await downloadKeycloakDefaultTheme({ keycloakVersion, - "destDirPath": tmpDirPath, + destDirPath: tmpDirPath, buildOptions }); const resourcesPath = pathJoin(themeDirPath, themeType, "resources"); transformCodebase({ - "srcDirPath": pathJoin(tmpDirPath, "keycloak", themeType, "resources"), - "destDirPath": resourcesPath + srcDirPath: pathJoin(tmpDirPath, "keycloak", themeType, "resources"), + destDirPath: resourcesPath }); transformCodebase({ - "srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"), - "destDirPath": pathJoin(resourcesPath, resources_common) + srcDirPath: pathJoin(tmpDirPath, "keycloak", "common", "resources"), + destDirPath: pathJoin(resourcesPath, resources_common) }); - rmSync(tmpDirPath, { "recursive": true }); + rmSync(tmpDirPath, { recursive: true }); } diff --git a/src/bin/shared/getJarFileBasename.ts b/src/bin/shared/getJarFileBasename.ts index 8c073ffc..5baf8524 100644 --- a/src/bin/shared/getJarFileBasename.ts +++ b/src/bin/shared/getJarFileBasename.ts @@ -1,6 +1,8 @@ import type { KeycloakVersionRange } from "./KeycloakVersionRange"; -export function getJarFileBasename(params: { keycloakVersionRange: KeycloakVersionRange }) { +export function getJarFileBasename(params: { + keycloakVersionRange: KeycloakVersionRange; +}) { const { keycloakVersionRange } = params; const jarFileBasename = `keycloak-theme-for-kc-${keycloakVersionRange}.jar`; diff --git a/src/bin/shared/getThemeSrcDirPath.ts b/src/bin/shared/getThemeSrcDirPath.ts index 08aaf659..e9644e12 100644 --- a/src/bin/shared/getThemeSrcDirPath.ts +++ b/src/bin/shared/getThemeSrcDirPath.ts @@ -12,7 +12,10 @@ export function getThemeSrcDirPath(params: { reactAppRootDirPath: string }) { const srcDirPath = pathJoin(reactAppRootDirPath, "src"); - const themeSrcDirPath: string | undefined = crawl({ "dirPath": srcDirPath, "returnedPathsType": "relative to dirPath" }) + const themeSrcDirPath: string | undefined = crawl({ + dirPath: srcDirPath, + returnedPathsType: "relative to dirPath" + }) .map(fileRelativePath => { for (const themeSrcDirBasename of themeSrcDirBasenames) { const split = fileRelativePath.split(themeSrcDirBasename); @@ -32,7 +35,7 @@ export function getThemeSrcDirPath(params: { reactAppRootDirPath: string }) { if (!fs.existsSync(pathJoin(srcDirPath, themeType))) { continue; } - return { "themeSrcDirPath": srcDirPath }; + return { themeSrcDirPath: srcDirPath }; } console.error( diff --git a/src/bin/shared/metaInfKeycloakThemes.ts b/src/bin/shared/metaInfKeycloakThemes.ts index 6592332c..4d4ce139 100644 --- a/src/bin/shared/metaInfKeycloakThemes.ts +++ b/src/bin/shared/metaInfKeycloakThemes.ts @@ -6,29 +6,56 @@ export type MetaInfKeycloakTheme = { themes: { name: string; types: (ThemeType | "email")[] }[]; }; -export function getMetaInfKeycloakThemesJsonFilePath(params: { keycloakifyBuildDirPath: string }) { +export function getMetaInfKeycloakThemesJsonFilePath(params: { + keycloakifyBuildDirPath: string; +}) { const { keycloakifyBuildDirPath } = params; - return pathJoin(keycloakifyBuildDirPath, "src", "main", "resources", "META-INF", "keycloak-themes.json"); + return pathJoin( + keycloakifyBuildDirPath, + "src", + "main", + "resources", + "META-INF", + "keycloak-themes.json" + ); } -export function readMetaInfKeycloakThemes(params: { keycloakifyBuildDirPath: string }): MetaInfKeycloakTheme { +export function readMetaInfKeycloakThemes(params: { + keycloakifyBuildDirPath: string; +}): MetaInfKeycloakTheme { const { keycloakifyBuildDirPath } = params; - return JSON.parse(fs.readFileSync(getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath })).toString("utf8")) as MetaInfKeycloakTheme; + return JSON.parse( + fs + .readFileSync( + getMetaInfKeycloakThemesJsonFilePath({ + keycloakifyBuildDirPath + }) + ) + .toString("utf8") + ) as MetaInfKeycloakTheme; } -export function writeMetaInfKeycloakThemes(params: { keycloakifyBuildDirPath: string; metaInfKeycloakThemes: MetaInfKeycloakTheme }) { +export function writeMetaInfKeycloakThemes(params: { + keycloakifyBuildDirPath: string; + metaInfKeycloakThemes: MetaInfKeycloakTheme; +}) { const { keycloakifyBuildDirPath, metaInfKeycloakThemes } = params; - const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath }); + const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({ + keycloakifyBuildDirPath + }); { const dirPath = pathDirname(metaInfKeycloakThemesJsonPath); if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { "recursive": true }); + fs.mkdirSync(dirPath, { recursive: true }); } } - fs.writeFileSync(metaInfKeycloakThemesJsonPath, Buffer.from(JSON.stringify(metaInfKeycloakThemes, null, 2), "utf8")); + fs.writeFileSync( + metaInfKeycloakThemesJsonPath, + Buffer.from(JSON.stringify(metaInfKeycloakThemes, null, 2), "utf8") + ); } diff --git a/src/bin/shared/promptKeycloakVersion.ts b/src/bin/shared/promptKeycloakVersion.ts index c1a5e431..557d4f70 100644 --- a/src/bin/shared/promptKeycloakVersion.ts +++ b/src/bin/shared/promptKeycloakVersion.ts @@ -7,19 +7,26 @@ import * as fs from "fs"; import type { ReturnType } from "tsafe"; import { id } from "tsafe/id"; -export async function promptKeycloakVersion(params: { startingFromMajor: number | undefined; cacheDirPath: string }) { +export async function promptKeycloakVersion(params: { + startingFromMajor: number | undefined; + cacheDirPath: string; +}) { const { startingFromMajor, cacheDirPath } = params; const { getLatestsSemVersionedTag } = (() => { const { octokit } = (() => { const githubToken = process.env.GITHUB_TOKEN; - const octokit = new Octokit(githubToken === undefined ? undefined : { "auth": githubToken }); + const octokit = new Octokit( + githubToken === undefined ? undefined : { auth: githubToken } + ); return { octokit }; })(); - const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ octokit }); + const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ + octokit + }); return { getLatestsSemVersionedTag }; })(); @@ -39,7 +46,9 @@ export async function promptKeycloakVersion(params: { startingFromMajor: number break use_cache; } - const cache: Cache = JSON.parse(fs.readFileSync(cacheFilePath).toString("utf8")); + const cache: Cache = JSON.parse( + fs.readFileSync(cacheFilePath).toString("utf8") + ); if (Date.now() - cache.time > 3_600_000) { fs.unlinkSync(cacheFilePath); @@ -50,16 +59,16 @@ export async function promptKeycloakVersion(params: { startingFromMajor: number } const semVersionedTags = await getLatestsSemVersionedTag({ - "count": 50, - "owner": "keycloak", - "repo": "keycloak" + count: 50, + owner: "keycloak", + repo: "keycloak" }); { const dirPath = pathDirname(cacheFilePath); if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { "recursive": true }); + fs.mkdirSync(dirPath, { recursive: true }); } } @@ -67,7 +76,7 @@ export async function promptKeycloakVersion(params: { startingFromMajor: number cacheFilePath, JSON.stringify( id({ - "time": Date.now(), + time: Date.now(), semVersionedTags }), null, @@ -79,23 +88,33 @@ export async function promptKeycloakVersion(params: { startingFromMajor: number })(); semVersionedTags.forEach(semVersionedTag => { - if (startingFromMajor !== undefined && semVersionedTag.version.major < startingFromMajor) { + if ( + startingFromMajor !== undefined && + semVersionedTag.version.major < startingFromMajor + ) { return; } - const currentSemVersionedTag = semVersionedTagByMajor.get(semVersionedTag.version.major); + const currentSemVersionedTag = semVersionedTagByMajor.get( + semVersionedTag.version.major + ); - if (currentSemVersionedTag !== undefined && SemVer.compare(semVersionedTag.version, currentSemVersionedTag.version) === -1) { + if ( + currentSemVersionedTag !== undefined && + SemVer.compare(semVersionedTag.version, currentSemVersionedTag.version) === -1 + ) { return; } semVersionedTagByMajor.set(semVersionedTag.version.major, semVersionedTag); }); - const lastMajorVersions = Array.from(semVersionedTagByMajor.values()).map(({ tag }) => tag); + const lastMajorVersions = Array.from(semVersionedTagByMajor.values()).map( + ({ tag }) => tag + ); const { value } = await cliSelect({ - "values": lastMajorVersions + values: lastMajorVersions }).catch(() => { process.exit(-1); }); diff --git a/src/bin/start-keycloak/myrealm-realm-24.json b/src/bin/start-keycloak/myrealm-realm-24.json index 7a44af4e..b4bf653a 100644 --- a/src/bin/start-keycloak/myrealm-realm-24.json +++ b/src/bin/start-keycloak/myrealm-realm-24.json @@ -407,7 +407,11 @@ "otpPolicyLookAheadWindow": 1, "otpPolicyPeriod": 30, "otpPolicyCodeReusable": false, - "otpSupportedApplications": ["totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName"], + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], "localizationTexts": {}, "webAuthnPolicyRpEntityName": "keycloak", "webAuthnPolicySignatureAlgorithms": ["ES256"], @@ -520,7 +524,12 @@ "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "bb874a19-9a92-4504-a7c0-d32ef6f3d266", @@ -562,7 +571,12 @@ } ], "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "e19ed660-ca30-4266-be25-7ac226994f0f", @@ -589,7 +603,12 @@ "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "2c000747-ea5b-4226-82a3-1fc32bc8a079", @@ -616,7 +635,12 @@ "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "5dfb0d1a-2ab1-480f-8bab-81502f762ac0", @@ -761,7 +785,12 @@ } ], "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "8efd01a0-40cd-487d-818b-fa2b096170e0", @@ -788,7 +817,12 @@ "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] }, { "id": "199b2e1b-2cdd-4d8b-8816-4a5c79741658", @@ -838,7 +872,12 @@ } ], "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] } ], "clientScopes": [ @@ -1379,8 +1418,20 @@ ] } ], - "defaultDefaultClientScopes": ["role_list", "profile", "email", "roles", "web-origins", "acr"], - "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt"], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins", + "acr" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], "browserSecurityHeaders": { "contentSecurityPolicyReportOnly": "", "xContentTypeOptions": "nosniff", @@ -1575,7 +1626,19 @@ ] }, "internationalizationEnabled": true, - "supportedLocales": ["ar", "de", "fi", "el", "ja", "en", "fa", "it", "fr", "ca", "es"], + "supportedLocales": [ + "ar", + "de", + "fi", + "el", + "ja", + "en", + "fa", + "it", + "fr", + "ca", + "es" + ], "defaultLocale": "en", "authenticationFlows": [ { diff --git a/src/bin/start-keycloak/start-keycloak.ts b/src/bin/start-keycloak/start-keycloak.ts index f79974cc..5c7891af 100644 --- a/src/bin/start-keycloak/start-keycloak.ts +++ b/src/bin/start-keycloak/start-keycloak.ts @@ -2,13 +2,22 @@ import { readBuildOptions } from "../shared/buildOptions"; import type { CliCommandOptions as CliCommandOptions_common } from "../main"; import { promptKeycloakVersion } from "../shared/promptKeycloakVersion"; import { readMetaInfKeycloakThemes } from "../shared/metaInfKeycloakThemes"; -import { accountV1ThemeName, skipBuildJarsEnvName, containerName } from "../shared/constants"; +import { + accountV1ThemeName, + skipBuildJarsEnvName, + containerName +} from "../shared/constants"; import { SemVer } from "../tools/SemVer"; import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange"; import { getJarFileBasename } from "../shared/getJarFileBasename"; import { assert, type Equals } from "tsafe/assert"; import * as fs from "fs"; -import { join as pathJoin, relative as pathRelative, sep as pathSep, posix as pathPosix } from "path"; +import { + join as pathJoin, + relative as pathRelative, + sep as pathSep, + posix as pathPosix +} from "path"; import * as child_process from "child_process"; import chalk from "chalk"; import chokidar from "chokidar"; @@ -30,7 +39,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) let commandOutput: Buffer | undefined = undefined; try { - commandOutput = child_process.execSync("docker --version", { "stdio": ["ignore", "pipe", "ignore"] }); + commandOutput = child_process.execSync("docker --version", { + stdio: ["ignore", "pipe", "ignore"] + }); } catch {} if (commandOutput?.toString("utf8").includes("Docker")) { @@ -40,7 +51,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) console.log( [ `${chalk.red("Docker required.")}`, - `Install it with Docker Desktop: ${chalk.bold.underline("https://www.docker.com/products/docker-desktop/")}`, + `Install it with Docker Desktop: ${chalk.bold.underline( + "https://www.docker.com/products/docker-desktop/" + )}`, `(or any other way)` ].join(" ") ); @@ -52,7 +65,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) let isDockerRunning: boolean; try { - child_process.execSync("docker info", { "stdio": "ignore" }); + child_process.execSync("docker info", { stdio: "ignore" }); isDockerRunning = true; } catch { isDockerRunning = false; @@ -62,7 +75,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) break exit_if_docker_not_running; } - console.log([`${chalk.red("Docker daemon is not running.")}`, `Please start Docker Desktop and try again.`].join(" ")); + console.log( + [ + `${chalk.red("Docker daemon is not running.")}`, + `Please start Docker Desktop and try again.` + ].join(" ") + ); process.exit(1); } @@ -77,51 +95,60 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } console.log( - [`${chalk.red("The theme has not been built.")}`, `Please run ${chalk.bold("npx vite && npx keycloakify build")} first.`].join(" ") + [ + `${chalk.red("The theme has not been built.")}`, + `Please run ${chalk.bold("npx vite && npx keycloakify build")} first.` + ].join(" ") ); process.exit(1); } const metaInfKeycloakThemes = readMetaInfKeycloakThemes({ - "keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath + keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath }); - const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(({ name }) => name === accountV1ThemeName); + const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some( + ({ name }) => name === accountV1ThemeName + ); - const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } = await (async function getKeycloakMajor(): Promise<{ - keycloakVersion: string; - keycloakMajorNumber: number; - }> { - if (cliCommandOptions.keycloakVersion !== undefined) { - return { - "keycloakVersion": cliCommandOptions.keycloakVersion, - "keycloakMajorNumber": SemVer.parse(cliCommandOptions.keycloakVersion).major - }; - } + const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } = + await (async function getKeycloakMajor(): Promise<{ + keycloakVersion: string; + keycloakMajorNumber: number; + }> { + if (cliCommandOptions.keycloakVersion !== undefined) { + return { + keycloakVersion: cliCommandOptions.keycloakVersion, + keycloakMajorNumber: SemVer.parse(cliCommandOptions.keycloakVersion) + .major + }; + } - console.log(chalk.cyan("On which version of Keycloak do you want to test your theme?")); - - const { keycloakVersion } = await promptKeycloakVersion({ - "startingFromMajor": 17, - "cacheDirPath": buildOptions.cacheDirPath - }); - - console.log(`→ ${keycloakVersion}`); - - const keycloakMajorNumber = SemVer.parse(keycloakVersion).major; - - if (doesImplementAccountTheme && keycloakMajorNumber === 22) { console.log( - [ - "Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22", - "Please select any other Keycloak version" - ].join(" ") + chalk.cyan("On which version of Keycloak do you want to test your theme?") ); - return getKeycloakMajor(); - } - return { keycloakVersion, keycloakMajorNumber }; - })(); + const { keycloakVersion } = await promptKeycloakVersion({ + startingFromMajor: 17, + cacheDirPath: buildOptions.cacheDirPath + }); + + console.log(`→ ${keycloakVersion}`); + + const keycloakMajorNumber = SemVer.parse(keycloakVersion).major; + + if (doesImplementAccountTheme && keycloakMajorNumber === 22) { + console.log( + [ + "Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22", + "Please select any other Keycloak version" + ].join(" ") + ); + return getKeycloakMajor(); + } + + return { keycloakVersion, keycloakMajorNumber }; + })(); const keycloakVersionRange: KeycloakVersionRange = (() => { if (doesImplementAccountTheme) { @@ -139,7 +166,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) return "24-and-above" as const; })(); - assert>(); + assert< + Equals + >(); return keycloakVersionRange; } else { @@ -151,7 +180,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) return "22-and-above" as const; })(); - assert>(); + assert< + Equals< + typeof keycloakVersionRange, + KeycloakVersionRange.WithoutAccountTheme + > + >(); return keycloakVersionRange; } @@ -163,7 +197,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const mountTargets = buildOptions.themeNames .map(themeName => { - const themeEntry = metaInfKeycloakThemes.themes.find(({ name }) => name === themeName); + const themeEntry = metaInfKeycloakThemes.themes.find( + ({ name }) => name === themeName + ); assert(themeEntry !== undefined); @@ -181,10 +217,24 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) return fs .readdirSync(localPathDirname) - .filter(fileOrDirectoryBasename => !fileOrDirectoryBasename.endsWith(".properties")) + .filter( + fileOrDirectoryBasename => + !fileOrDirectoryBasename.endsWith(".properties") + ) .map(fileOrDirectoryBasename => ({ - "localPath": pathJoin(localPathDirname, fileOrDirectoryBasename), - "containerPath": pathPosix.join("/", "opt", "keycloak", "themes", themeName, themeType, fileOrDirectoryBasename) + localPath: pathJoin( + localPathDirname, + fileOrDirectoryBasename + ), + containerPath: pathPosix.join( + "/", + "opt", + "keycloak", + "themes", + themeName, + themeType, + fileOrDirectoryBasename + ) })); }) .flat(); @@ -192,33 +242,56 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) .flat(); try { - child_process.execSync(`docker rm --force ${containerName}`, { "stdio": "ignore" }); + child_process.execSync(`docker rm --force ${containerName}`, { + stdio: "ignore" + }); } catch {} const realmJsonFilePath = await (async () => { if (cliCommandOptions.realmJsonFilePath !== undefined) { - console.log(chalk.green(`Using realm json file: ${cliCommandOptions.realmJsonFilePath}`)); + console.log( + chalk.green( + `Using realm json file: ${cliCommandOptions.realmJsonFilePath}` + ) + ); return getAbsoluteAndInOsFormatPath({ - "pathIsh": cliCommandOptions.realmJsonFilePath, - "cwd": process.cwd() + pathIsh: cliCommandOptions.realmJsonFilePath, + cwd: process.cwd() }); } - const dirPath = pathJoin(getThisCodebaseRootDirPath(), "src", "bin", "start-keycloak"); + const dirPath = pathJoin( + getThisCodebaseRootDirPath(), + "src", + "bin", + "start-keycloak" + ); - const filePath = pathJoin(dirPath, `myrealm-realm-${keycloakMajorVersionNumber}.json`); + const filePath = pathJoin( + dirPath, + `myrealm-realm-${keycloakMajorVersionNumber}.json` + ); if (fs.existsSync(filePath)) { return filePath; } - console.log(`${chalk.yellow(`Keycloakify do not have a realm configuration for Keycloak ${keycloakMajorVersionNumber} yet.`)}`); + console.log( + `${chalk.yellow( + `Keycloakify do not have a realm configuration for Keycloak ${keycloakMajorVersionNumber} yet.` + )}` + ); console.log(chalk.cyan("Select what configuration to use:")); const { value } = await cliSelect({ - "values": [...fs.readdirSync(dirPath).filter(fileBasename => fileBasename.endsWith(".json")), "none"] + values: [ + ...fs + .readdirSync(dirPath) + .filter(fileBasename => fileBasename.endsWith(".json")), + "none" + ] }).catch(() => { process.exit(-1); }); @@ -238,17 +311,37 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) ...["--name", containerName], ...["-e", "KEYCLOAK_ADMIN=admin"], ...["-e", "KEYCLOAK_ADMIN_PASSWORD=admin"], - ...(realmJsonFilePath === undefined ? [] : ["-v", `${realmJsonFilePath}:/opt/keycloak/data/import/myrealm-realm.json`]), - ...["-v", `${pathJoin(buildOptions.keycloakifyBuildDirPath, jarFileBasename)}:/opt/keycloak/providers/keycloak-theme.jar`], - ...(keycloakMajorVersionNumber <= 20 ? ["-e", "JAVA_OPTS=-Dkeycloak.profile=preview"] : []), - ...mountTargets.map(({ localPath, containerPath }) => ["-v", `${localPath}:${containerPath}:rw`]).flat(), + ...(realmJsonFilePath === undefined + ? [] + : [ + "-v", + `${realmJsonFilePath}:/opt/keycloak/data/import/myrealm-realm.json` + ]), + ...[ + "-v", + `${pathJoin( + buildOptions.keycloakifyBuildDirPath, + jarFileBasename + )}:/opt/keycloak/providers/keycloak-theme.jar` + ], + ...(keycloakMajorVersionNumber <= 20 + ? ["-e", "JAVA_OPTS=-Dkeycloak.profile=preview"] + : []), + ...mountTargets + .map(({ localPath, containerPath }) => [ + "-v", + `${localPath}:${containerPath}:rw` + ]) + .flat(), `quay.io/keycloak/keycloak:${keycloakVersion}`, "start-dev", - ...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24 ? ["--features=declarative-user-profile"] : []), + ...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24 + ? ["--features=declarative-user-profile"] + : []), ...(realmJsonFilePath === undefined ? [] : ["--import-realm"]) ], { - "cwd": buildOptions.keycloakifyBuildDirPath + cwd: buildOptions.keycloakifyBuildDirPath } ] as const; @@ -278,17 +371,23 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) [ "", `${chalk.green("Your theme is accessible at:")}`, - `${chalk.green("➜")} ${chalk.cyan.bold("https://my-theme.keycloakify.dev/")}`, + `${chalk.green("➜")} ${chalk.cyan.bold( + "https://my-theme.keycloakify.dev/" + )}`, "", "You can login with the following credentials:", `- username: ${chalk.cyan.bold("testuser")}`, `- password: ${chalk.cyan.bold("password123")}`, "", - `Keycloak Admin console: ${chalk.cyan.bold(`http://localhost:${cliCommandOptions.port}`)}`, + `Keycloak Admin console: ${chalk.cyan.bold( + `http://localhost:${cliCommandOptions.port}` + )}`, `- user: ${chalk.cyan.bold("admin")}`, `- password: ${chalk.cyan.bold("admin")}`, "", - `Watching for changes in ${chalk.bold(`.${pathSep}${pathRelative(process.cwd(), srcDirPath)}`)}` + `Watching for changes in ${chalk.bold( + `.${pathSep}${pathRelative(process.cwd(), srcDirPath)}` + )}` ].join("\n") ); }; @@ -297,75 +396,79 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } { - const { waitForDebounce } = waitForDebounceFactory({ "delay": 400 }); + const { waitForDebounce } = waitForDebounceFactory({ delay: 400 }); - chokidar.watch([srcDirPath, getThisCodebaseRootDirPath()], { "ignoreInitial": true }).on("all", async (...[, filePath]) => { - if ( - isInside({ - "dirPath": pathJoin(getThisCodebaseRootDirPath(), "src", "bin"), - filePath - }) || - isInside({ - "dirPath": pathJoin(getThisCodebaseRootDirPath(), "bin"), - filePath - }) - ) { - return; - } + chokidar + .watch([srcDirPath, getThisCodebaseRootDirPath()], { + ignoreInitial: true + }) + .on("all", async (...[, filePath]) => { + if ( + isInside({ + dirPath: pathJoin(getThisCodebaseRootDirPath(), "src", "bin"), + filePath + }) || + isInside({ + dirPath: pathJoin(getThisCodebaseRootDirPath(), "bin"), + filePath + }) + ) { + return; + } - await waitForDebounce(); + await waitForDebounce(); - console.log(chalk.cyan("Detected changes in the theme. Rebuilding ...")); + console.log(chalk.cyan("Detected changes in the theme. Rebuilding ...")); - const dViteBuildDone = new Deferred(); + const dViteBuildDone = new Deferred(); - { - const child = child_process.spawn("npx", ["vite", "build"], { - "cwd": buildOptions.reactAppRootDirPath, - "env": process.env - }); + { + const child = child_process.spawn("npx", ["vite", "build"], { + cwd: buildOptions.reactAppRootDirPath, + env: process.env + }); - child.stdout.on("data", data => { - if (data.toString("utf8").includes("gzip:")) { - return; - } + child.stdout.on("data", data => { + if (data.toString("utf8").includes("gzip:")) { + return; + } - process.stdout.write(data); - }); + process.stdout.write(data); + }); - child.stderr.on("data", data => process.stderr.write(data)); + child.stderr.on("data", data => process.stderr.write(data)); - child.on("exit", code => { - if (code === 0) { - dViteBuildDone.resolve(); - } - }); - } + child.on("exit", code => { + if (code === 0) { + dViteBuildDone.resolve(); + } + }); + } - await dViteBuildDone.pr; + await dViteBuildDone.pr; - { - const child = child_process.spawn("npx", ["keycloakify", "build"], { - "cwd": buildOptions.reactAppRootDirPath, - "env": { - ...process.env, - [skipBuildJarsEnvName]: "true" - } - }); + { + const child = child_process.spawn("npx", ["keycloakify", "build"], { + cwd: buildOptions.reactAppRootDirPath, + env: { + ...process.env, + [skipBuildJarsEnvName]: "true" + } + }); - child.stdout.on("data", data => process.stdout.write(data)); + child.stdout.on("data", data => process.stdout.write(data)); - child.stderr.on("data", data => process.stderr.write(data)); + child.stderr.on("data", data => process.stderr.write(data)); - child.on("exit", code => { - if (code !== 0) { - console.log(chalk.yellow("Theme not updated, build failed")); - return; - } + child.on("exit", code => { + if (code !== 0) { + console.log(chalk.yellow("Theme not updated, build failed")); + return; + } - console.log(chalk.green("Rebuild done")); - }); - } - }); + console.log(chalk.green("Rebuild done")); + }); + } + }); } } diff --git a/src/bin/tools/SemVer.ts b/src/bin/tools/SemVer.ts index f8db9c3a..5a7b3d93 100644 --- a/src/bin/tools/SemVer.ts +++ b/src/bin/tools/SemVer.ts @@ -12,35 +12,39 @@ export namespace SemVer { export type BumpType = (typeof bumpTypes)[number]; export function parse(versionStr: string): SemVer { - const match = versionStr.match(/^v?([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-rc.([0-9]+))?$/); + const match = versionStr.match( + /^v?([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-rc.([0-9]+))?$/ + ); if (!match) { throw new Error(`${versionStr} is not a valid semantic version`); } const semVer: Omit = { - "major": parseInt(match[1]), - "minor": parseInt(match[2]), - "patch": (() => { + major: parseInt(match[1]), + minor: parseInt(match[2]), + patch: (() => { const str = match[3]; return str === undefined ? 0 : parseInt(str); })(), ...(() => { const str = match[4]; - return str === undefined ? {} : { "rc": parseInt(str) }; + return str === undefined ? {} : { rc: parseInt(str) }; })() }; const initialStr = stringify(semVer); Object.defineProperty(semVer, "parsedFrom", { - "enumerable": true, - "get": function () { + enumerable: true, + get: function () { const currentStr = stringify(this); if (currentStr !== initialStr) { - throw new Error(`SemVer.parsedFrom can't be read anymore, the version have been modified from ${initialStr} to ${currentStr}`); + throw new Error( + `SemVer.parsedFrom can't be read anymore, the version have been modified from ${initialStr} to ${currentStr}` + ); } return versionStr; @@ -51,7 +55,9 @@ export namespace SemVer { } export function stringify(v: Omit): string { - return `${v.major}.${v.minor}.${v.patch}${v.rc === undefined ? "" : `-rc.${v.rc}`}`; + return `${v.major}.${v.minor}.${v.patch}${ + v.rc === undefined ? "" : `-rc.${v.rc}` + }`; } /** @@ -80,12 +86,25 @@ export namespace SemVer { console.log(compare(parse("3.0.0-rc.3"), parse("4.0.0")) === -1 ) */ - export function bumpType(params: { versionBehind: string | SemVer; versionAhead: string | SemVer }): BumpType | "no bump" { - const versionAhead = typeof params.versionAhead === "string" ? parse(params.versionAhead) : params.versionAhead; - const versionBehind = typeof params.versionBehind === "string" ? parse(params.versionBehind) : params.versionBehind; + export function bumpType(params: { + versionBehind: string | SemVer; + versionAhead: string | SemVer; + }): BumpType | "no bump" { + const versionAhead = + typeof params.versionAhead === "string" + ? parse(params.versionAhead) + : params.versionAhead; + const versionBehind = + typeof params.versionBehind === "string" + ? parse(params.versionBehind) + : params.versionBehind; if (compare(versionBehind, versionAhead) === 1) { - throw new Error(`Version regression ${stringify(versionBehind)} -> ${stringify(versionAhead)}`); + throw new Error( + `Version regression ${stringify(versionBehind)} -> ${stringify( + versionAhead + )}` + ); } for (const level of ["major", "minor", "patch", "rc"] as const) { diff --git a/src/bin/tools/String.prototype.replaceAll.ts b/src/bin/tools/String.prototype.replaceAll.ts index 7fc1ebb8..c295733d 100644 --- a/src/bin/tools/String.prototype.replaceAll.ts +++ b/src/bin/tools/String.prototype.replaceAll.ts @@ -1,4 +1,8 @@ -export function replaceAll(string: string, searchValue: string | RegExp, replaceValue: string): string { +export function replaceAll( + string: string, + searchValue: string | RegExp, + replaceValue: string +): string { if ((string as any).replaceAll !== undefined) { return (string as any).replaceAll(searchValue, replaceValue); } @@ -24,7 +28,10 @@ export function replaceAll(string: string, searchValue: string | RegExp, replace // Convert searchValue to string if it's not a string or RegExp var searchString = String(searchValue); - var regexFromString = new RegExp(searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"); + var regexFromString = new RegExp( + searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), + "g" + ); return string.replace(regexFromString, replaceValue); } diff --git a/src/bin/tools/crawl.ts b/src/bin/tools/crawl.ts index c83a6e54..86ba2078 100644 --- a/src/bin/tools/crawl.ts +++ b/src/bin/tools/crawl.ts @@ -16,7 +16,10 @@ const crawlRec = (dirPath: string, filePaths: string[]) => { }; /** List all files in a given directory return paths relative to the dir_path */ -export function crawl(params: { dirPath: string; returnedPathsType: "absolute" | "relative to dirPath" }): string[] { +export function crawl(params: { + dirPath: string; + returnedPathsType: "absolute" | "relative to dirPath"; +}): string[] { const { dirPath, returnedPathsType } = params; const filePaths: string[] = []; diff --git a/src/bin/tools/crc32.ts b/src/bin/tools/crc32.ts index 85f8f0bc..fbfacfba 100644 --- a/src/bin/tools/crc32.ts +++ b/src/bin/tools/crc32.ts @@ -1,27 +1,42 @@ import { Readable } from "stream"; const crc32tab = [ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, + 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, + 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, + 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, + 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, + 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, + 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, + 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, + 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, + 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, + 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, + 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, + 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, + 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, + 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, + 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, + 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, + 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ]; @@ -33,11 +48,13 @@ const crc32tab = [ export function crc32(input: Readable | String | Buffer): Promise { if (typeof input === "string") { let crc = ~0; - for (let i = 0; i < input.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ input.charCodeAt(i)) & 0xff]; + for (let i = 0; i < input.length; i++) + crc = (crc >>> 8) ^ crc32tab[(crc ^ input.charCodeAt(i)) & 0xff]; return Promise.resolve((crc ^ -1) >>> 0); } else if (input instanceof Buffer) { let crc = ~0; - for (let i = 0; i < input.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ input[i]) & 0xff]; + for (let i = 0; i < input.length; i++) + crc = (crc >>> 8) ^ crc32tab[(crc ^ input[i]) & 0xff]; return Promise.resolve((crc ^ -1) >>> 0); } else if (input instanceof Readable) { return new Promise((resolve, reject) => { @@ -46,7 +63,8 @@ export function crc32(input: Readable | String | Buffer): Promise { input.on("end", () => resolve((crc ^ -1) >>> 0)); input.on("error", e => reject(e)); input.on("data", (chunk: Buffer) => { - for (let i = 0; i < chunk.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ chunk[i]) & 0xff]; + for (let i = 0; i < chunk.length; i++) + crc = (crc >>> 8) ^ crc32tab[(crc ^ chunk[i]) & 0xff]; }); }); } else { diff --git a/src/bin/tools/fetchProxyOptions.ts b/src/bin/tools/fetchProxyOptions.ts index a6e880fd..3a903d6b 100644 --- a/src/bin/tools/fetchProxyOptions.ts +++ b/src/bin/tools/fetchProxyOptions.ts @@ -11,7 +11,10 @@ function ensureSingleOrNone(arg0: T | T[]) { if (!Array.isArray(arg0)) return arg0; if (arg0.length === 0) return undefined; if (arg0.length === 1) return arg0[0]; - throw new Error("Illegal configuration, expected a single value but found multiple: " + arg0.map(String).join(", ")); + throw new Error( + "Illegal configuration, expected a single value but found multiple: " + + arg0.map(String).join(", ") + ); } type NPMConfig = Record; @@ -24,10 +27,15 @@ async function getNmpConfig(params: { npmWorkspaceRootDirPath: string }) { const exec = promisify(execCallback); - const stdout = await exec("npm config get", { "encoding": "utf8", "cwd": npmWorkspaceRootDirPath }).then(({ stdout }) => stdout); + const stdout = await exec("npm config get", { + encoding: "utf8", + cwd: npmWorkspaceRootDirPath + }).then(({ stdout }) => stdout); const npmConfigReducer = (cfg: NPMConfig, [key, value]: [string, string]) => - key in cfg ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] } : { ...cfg, [key]: value }; + key in cfg + ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] } + : { ...cfg, [key]: value }; return stdout .split("\n") @@ -37,9 +45,14 @@ async function getNmpConfig(params: { npmWorkspaceRootDirPath: string }) { .reduce(npmConfigReducer, {} as NPMConfig); } -export type ProxyFetchOptions = Pick; +export type ProxyFetchOptions = Pick< + FetchOptions, + "proxy" | "noProxy" | "strictSSL" | "cert" | "ca" +>; -export async function getProxyFetchOptions(params: { npmWorkspaceRootDirPath: string }): Promise { +export async function getProxyFetchOptions(params: { + npmWorkspaceRootDirPath: string; +}): Promise { const { npmWorkspaceRootDirPath } = params; const cfg = await getNmpConfig({ npmWorkspaceRootDirPath }); @@ -60,14 +73,24 @@ export async function getProxyFetchOptions(params: { npmWorkspaceRootDirPath: st ca.push( ...(await (async () => { function chunks(arr: T[], size: number = 2) { - return arr.map((_, i) => i % size == 0 && arr.slice(i, i + size)).filter(Boolean) as T[][]; + return arr + .map((_, i) => i % size == 0 && arr.slice(i, i + size)) + .filter(Boolean) as T[][]; } const cafileContent = await readFile(cafile, "utf-8"); - return chunks(cafileContent.split(/(-----END CERTIFICATE-----)/), 2).map(ca => ca.join("").replace(/^\n/, "").replace(/\n/g, "\\n")); + return chunks(cafileContent.split(/(-----END CERTIFICATE-----)/), 2).map( + ca => ca.join("").replace(/^\n/, "").replace(/\n/g, "\\n") + ); })()) ); } - return { proxy, noProxy, strictSSL, cert, "ca": ca.length === 0 ? undefined : ca }; + return { + proxy, + noProxy, + strictSSL, + cert, + ca: ca.length === 0 ? undefined : ca + }; } diff --git a/src/bin/tools/getAbsoluteAndInOsFormatPath.ts b/src/bin/tools/getAbsoluteAndInOsFormatPath.ts index a21ef70d..bcabbd40 100644 --- a/src/bin/tools/getAbsoluteAndInOsFormatPath.ts +++ b/src/bin/tools/getAbsoluteAndInOsFormatPath.ts @@ -1,7 +1,15 @@ -import { isAbsolute as pathIsAbsolute, sep as pathSep, join as pathJoin, resolve as pathResolve } from "path"; +import { + isAbsolute as pathIsAbsolute, + sep as pathSep, + join as pathJoin, + resolve as pathResolve +} from "path"; import * as os from "os"; -export function getAbsoluteAndInOsFormatPath(params: { pathIsh: string; cwd: string }): string { +export function getAbsoluteAndInOsFormatPath(params: { + pathIsh: string; + cwd: string; +}): string { const { pathIsh, cwd } = params; let pathOut = pathIsh; diff --git a/src/bin/tools/getNpmWorkspaceRootDirPath.ts b/src/bin/tools/getNpmWorkspaceRootDirPath.ts index 8bb46720..4d2bf2aa 100644 --- a/src/bin/tools/getNpmWorkspaceRootDirPath.ts +++ b/src/bin/tools/getNpmWorkspaceRootDirPath.ts @@ -3,14 +3,22 @@ import { join as pathJoin, resolve as pathResolve, sep as pathSep } from "path"; import { assert } from "tsafe/assert"; import * as fs from "fs"; -export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string; dependencyExpected: string }) { +export function getNpmWorkspaceRootDirPath(params: { + reactAppRootDirPath: string; + dependencyExpected: string; +}) { const { reactAppRootDirPath, dependencyExpected } = params; const npmWorkspaceRootDirPath = (function callee(depth: number): string { - const cwd = pathResolve(pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")])); + const cwd = pathResolve( + pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")]) + ); try { - child_process.execSync("npm config get", { cwd, "stdio": "ignore" }); + child_process.execSync("npm config get", { + cwd, + stdio: "ignore" + }); } catch (error) { if (String(error).includes("ENOWORKSPACES")) { assert(cwd !== pathSep, "NPM workspace not found"); @@ -26,11 +34,16 @@ export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string assert(fs.existsSync(packageJsonFilePath)); - const parsedPackageJson = JSON.parse(fs.readFileSync(packageJsonFilePath).toString("utf8")); + const parsedPackageJson = JSON.parse( + fs.readFileSync(packageJsonFilePath).toString("utf8") + ); let isExpectedDependencyFound = false; - for (const dependenciesOrDevDependencies of ["dependencies", "devDependencies"] as const) { + for (const dependenciesOrDevDependencies of [ + "dependencies", + "devDependencies" + ] as const) { const dependencies = parsedPackageJson[dependenciesOrDevDependencies]; if (dependencies === undefined) { diff --git a/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts b/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts index 92c7ffb6..570e509c 100644 --- a/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +++ b/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts @@ -5,7 +5,11 @@ import { SemVer } from "../SemVer"; export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) { const { octokit } = params; - async function getLatestsSemVersionedTag(params: { owner: string; repo: string; count: number }): Promise< + async function getLatestsSemVersionedTag(params: { + owner: string; + repo: string; + count: number; + }): Promise< { tag: string; version: SemVer; @@ -33,7 +37,9 @@ export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) { semVersionedTags.push({ tag, version }); } - return semVersionedTags.sort(({ version: vX }, { version: vY }) => SemVer.compare(vY, vX)).slice(0, count); + return semVersionedTags + .sort(({ version: vX }, { version: vY }) => SemVer.compare(vY, vX)) + .slice(0, count); } return { getLatestsSemVersionedTag }; diff --git a/src/bin/tools/octokit-addons/listTags.ts b/src/bin/tools/octokit-addons/listTags.ts index 21a361c0..835e9f42 100644 --- a/src/bin/tools/octokit-addons/listTags.ts +++ b/src/bin/tools/octokit-addons/listTags.ts @@ -5,11 +5,19 @@ const per_page = 99; export function listTagsFactory(params: { octokit: Octokit }) { const { octokit } = params; - const octokit_repo_listTags = async (params: { owner: string; repo: string; per_page: number; page: number }) => { + const octokit_repo_listTags = async (params: { + owner: string; + repo: string; + per_page: number; + page: number; + }) => { return octokit.repos.listTags(params); }; - async function* listTags(params: { owner: string; repo: string }): AsyncGenerator { + async function* listTags(params: { + owner: string; + repo: string; + }): AsyncGenerator { const { owner, repo } = params; let page = 1; @@ -19,7 +27,7 @@ export function listTagsFactory(params: { octokit: Octokit }) { owner, repo, per_page, - "page": page++ + page: page++ }); for (const branch of resp.data.map(({ name }) => name)) { @@ -33,7 +41,10 @@ export function listTagsFactory(params: { octokit: Octokit }) { } /** Returns the same "latest" tag as deno.land/x, not actually the latest though */ - async function getLatestTag(params: { owner: string; repo: string }): Promise { + async function getLatestTag(params: { + owner: string; + repo: string; + }): Promise { const { owner, repo } = params; const itRes = await listTags({ owner, repo }).next(); diff --git a/src/bin/tools/partitionPromiseSettledResults.ts b/src/bin/tools/partitionPromiseSettledResults.ts index d52eb737..c682790b 100644 --- a/src/bin/tools/partitionPromiseSettledResults.ts +++ b/src/bin/tools/partitionPromiseSettledResults.ts @@ -2,10 +2,19 @@ export type PromiseSettledAndPartitioned = [T[], any[]]; export function partitionPromiseSettledResults() { return [ - ([successes, failures]: PromiseSettledAndPartitioned, item: PromiseSettledResult) => + ( + [successes, failures]: PromiseSettledAndPartitioned, + item: PromiseSettledResult + ) => item.status === "rejected" - ? ([successes, [item.reason, ...failures]] as PromiseSettledAndPartitioned) - : ([[item.value, ...successes], failures] as PromiseSettledAndPartitioned), + ? ([ + successes, + [item.reason, ...failures] + ] as PromiseSettledAndPartitioned) + : ([ + [item.value, ...successes], + failures + ] as PromiseSettledAndPartitioned), [[], []] as PromiseSettledAndPartitioned ] as const; } diff --git a/src/bin/tools/readThisNpmPackageVersion.ts b/src/bin/tools/readThisNpmPackageVersion.ts index 88eadbb6..b493c991 100644 --- a/src/bin/tools/readThisNpmPackageVersion.ts +++ b/src/bin/tools/readThisNpmPackageVersion.ts @@ -4,7 +4,11 @@ import * as fs from "fs"; import { join as pathJoin } from "path"; export function readThisNpmPackageVersion(): string { - const version = JSON.parse(fs.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json")).toString("utf8"))["version"]; + const version = JSON.parse( + fs + .readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json")) + .toString("utf8") + )["version"]; assert(typeof version === "string"); diff --git a/src/bin/tools/transformCodebase.ts b/src/bin/tools/transformCodebase.ts index 57aa41f2..94957244 100644 --- a/src/bin/tools/transformCodebase.ts +++ b/src/bin/tools/transformCodebase.ts @@ -3,7 +3,11 @@ import * as path from "path"; import { crawl } from "./crawl"; import { rmSync } from "../tools/fs.rmSync"; -type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string; fileRelativePath: string }) => +type TransformSourceCode = (params: { + sourceCode: Buffer; + filePath: string; + fileRelativePath: string; +}) => | { modifiedSourceCode: Buffer; newFileName?: string; @@ -15,18 +19,27 @@ type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string; file * If source and destination are the same this function can be used to apply the transformation in place * like filtering out some files or modifying them. * */ -export function transformCodebase(params: { srcDirPath: string; destDirPath: string; transformSourceCode?: TransformSourceCode }) { +export function transformCodebase(params: { + srcDirPath: string; + destDirPath: string; + transformSourceCode?: TransformSourceCode; +}) { const { srcDirPath, transformSourceCode } = params; const isTargetSameAsSource = path.relative(srcDirPath, params.destDirPath) === ""; - const destDirPath = isTargetSameAsSource ? path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs") : params.destDirPath; + const destDirPath = isTargetSameAsSource + ? path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs") + : params.destDirPath; fs.mkdirSync(destDirPath, { - "recursive": true + recursive: true }); - for (const fileRelativePath of crawl({ "dirPath": srcDirPath, "returnedPathsType": "relative to dirPath" })) { + for (const fileRelativePath of crawl({ + dirPath: srcDirPath, + returnedPathsType: "relative to dirPath" + })) { const filePath = path.join(srcDirPath, fileRelativePath); const destFilePath = path.join(destDirPath, fileRelativePath); @@ -34,7 +47,7 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str // it using the lower level implementation. if (transformSourceCode === undefined) { fs.mkdirSync(path.dirname(destFilePath), { - "recursive": true + recursive: true }); fs.copyFileSync(filePath, destFilePath); @@ -43,7 +56,7 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str } const transformSourceCodeResult = transformSourceCode({ - "sourceCode": fs.readFileSync(filePath), + sourceCode: fs.readFileSync(filePath), filePath, fileRelativePath }); @@ -53,16 +66,22 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str } fs.mkdirSync(path.dirname(destFilePath), { - "recursive": true + recursive: true }); const { newFileName, modifiedSourceCode } = transformSourceCodeResult; - fs.writeFileSync(path.join(path.dirname(destFilePath), newFileName ?? path.basename(destFilePath)), modifiedSourceCode); + fs.writeFileSync( + path.join( + path.dirname(destFilePath), + newFileName ?? path.basename(destFilePath) + ), + modifiedSourceCode + ); } if (isTargetSameAsSource) { - rmSync(srcDirPath, { "recursive": true }); + rmSync(srcDirPath, { recursive: true }); fs.renameSync(destDirPath, srcDirPath); } diff --git a/src/bin/tools/trimIndent.ts b/src/bin/tools/trimIndent.ts index ed486e50..642de778 100644 --- a/src/bin/tools/trimIndent.ts +++ b/src/bin/tools/trimIndent.ts @@ -14,7 +14,10 @@ function populateTemplate(strings: TemplateStringsArray, ...args: unknown[]) { if (args[i]) { // if the interpolation value has newlines, indent the interpolation values // using the last known string indent - const chunk = String(args[i]).replace(/([\r?\n])/g, "$1" + " ".repeat(lastStringLineLength)); + const chunk = String(args[i]).replace( + /([\r?\n])/g, + "$1" + " ".repeat(lastStringLineLength) + ); chunks.push(chunk); } } diff --git a/src/bin/tools/unzip.ts b/src/bin/tools/unzip.ts index eee80721..eb4827be 100644 --- a/src/bin/tools/unzip.ts +++ b/src/bin/tools/unzip.ts @@ -22,7 +22,11 @@ async function pathExists(path: string) { // Handlings of non posix path is not implemented correctly // it work by coincidence. Don't have the time to fix but it should be fixed. -export async function unzip(file: string, targetFolder: string, specificDirsToExtract?: string[]) { +export async function unzip( + file: string, + targetFolder: string, + specificDirsToExtract?: string[] +) { specificDirsToExtract = specificDirsToExtract?.map(dirPath => { if (!dirPath.endsWith("/") || !dirPath.endsWith("\\")) { dirPath += "/"; @@ -49,7 +53,9 @@ export async function unzip(file: string, targetFolder: string, specificDirsToEx zipfile.on("entry", async entry => { if (specificDirsToExtract !== undefined) { - const dirPath = specificDirsToExtract.find(dirPath => entry.fileName.startsWith(dirPath)); + const dirPath = specificDirsToExtract.find(dirPath => + entry.fileName.startsWith(dirPath) + ); // Skip files outside of the unzipSubPath if (dirPath === undefined) { @@ -85,7 +91,9 @@ export async function unzip(file: string, targetFolder: string, specificDirsToEx return; } - await fsp.mkdir(path.dirname(target), { "recursive": true }); + await fsp.mkdir(path.dirname(target), { + recursive: true + }); await pipeline(readStream, fs.createWriteStream(target)); diff --git a/src/lib/isStorybook.ts b/src/lib/isStorybook.ts index f684e7c8..cb070f9a 100644 --- a/src/lib/isStorybook.ts +++ b/src/lib/isStorybook.ts @@ -1 +1,3 @@ -export const isStorybook = typeof window === "object" && Object.keys(window).find(key => key.startsWith("__STORYBOOK")) !== undefined; +export const isStorybook = + typeof window === "object" && + Object.keys(window).find(key => key.startsWith("__STORYBOOK")) !== undefined; diff --git a/src/lib/useGetClassName.ts b/src/lib/useGetClassName.ts index 0d46ddbf..01e33215 100644 --- a/src/lib/useGetClassName.ts +++ b/src/lib/useGetClassName.ts @@ -1,14 +1,23 @@ import { clsx } from "keycloakify/tools/clsx"; import { useConstCallback } from "keycloakify/tools/useConstCallback"; -export function createUseClassName(params: { defaultClasses: Record }) { +export function createUseClassName(params: { + defaultClasses: Record; +}) { const { defaultClasses } = params; - function useGetClassName(params: { doUseDefaultCss: boolean; classes: Partial> | undefined }) { + function useGetClassName(params: { + doUseDefaultCss: boolean; + classes: Partial> | undefined; + }) { const { classes, doUseDefaultCss } = params; const getClassName = useConstCallback((classKey: ClassKey): string => { - return clsx(classKey, doUseDefaultCss ? defaultClasses[classKey] : undefined, classes?.[classKey]); + return clsx( + classKey, + doUseDefaultCss ? defaultClasses[classKey] : undefined, + classes?.[classKey] + ); }); return { getClassName }; diff --git a/src/login/Template.tsx b/src/login/Template.tsx index 0d3a61a4..0913ff64 100644 --- a/src/login/Template.tsx +++ b/src/login/Template.tsx @@ -41,13 +41,13 @@ export default function Template(props: TemplateProps) { }, []); useSetClassName({ - "qualifiedName": "html", - "className": getClassName("kcHtmlClass") + qualifiedName: "html", + className: getClassName("kcHtmlClass") }); useSetClassName({ - "qualifiedName": "body", - "className": bodyClassName ?? getClassName("kcBodyClass") + qualifiedName: "body", + className: bodyClassName ?? getClassName("kcBodyClass") }); useEffect(() => { @@ -63,7 +63,7 @@ export default function Template(props: TemplateProps) { }, []); const { areAllStyleSheetsLoaded } = useInsertLinkTags({ - "hrefs": !doUseDefaultCss + hrefs: !doUseDefaultCss ? [] : [ `${url.resourcesCommonPath}/node_modules/@patternfly/patternfly/patternfly.min.css`, @@ -75,17 +75,17 @@ export default function Template(props: TemplateProps) { }); const { insertScriptTags } = useInsertScriptTags({ - "scriptTags": [ + scriptTags: [ { - "type": "module", - "src": `${url.resourcesPath}/js/menu-button-links.js` + type: "module", + src: `${url.resourcesPath}/js/menu-button-links.js` }, ...(authenticationSession === undefined ? [] : [ { - "type": "module", - "textContent": [ + type: "module", + textContent: [ `import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";`, ``, `checkCookiesAndSetTimer(`, @@ -99,8 +99,8 @@ export default function Template(props: TemplateProps) { ...scripts.map( script => ({ - "type": "text/javascript", - "src": script + type: "text/javascript", + src: script } as const) ) ] @@ -237,7 +237,7 @@ export default function Template(props: TemplateProps) { diff --git a/src/login/TemplateProps.ts b/src/login/TemplateProps.ts index c6503daf..eebbae02 100644 --- a/src/login/TemplateProps.ts +++ b/src/login/TemplateProps.ts @@ -2,7 +2,10 @@ import type { ReactNode } from "react"; import type { KcContext } from "./kcContext"; import type { I18n } from "./i18n"; -export type TemplateProps = { +export type TemplateProps< + KcContext extends KcContext.Common, + I18nExtended extends I18n +> = { kcContext: KcContext; i18n: I18nExtended; doUseDefaultCss: boolean; diff --git a/src/login/UserProfileFormFields.tsx b/src/login/UserProfileFormFields.tsx index e145f168..98418317 100644 --- a/src/login/UserProfileFormFields.tsx +++ b/src/login/UserProfileFormFields.tsx @@ -43,7 +43,7 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps) onIsFormSubmittableValueChange(isFormSubmittable); }, [isFormSubmittable]); - const groupNameRef = { "current": "" }; + const groupNameRef = { current: "" }; return ( <> @@ -62,7 +62,9 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps) )}