keycloak_theme/src/bin/shared/buildContext.ts

1008 lines
35 KiB
TypeScript
Raw Normal View History

2022-08-16 14:41:06 +07:00
import { parse as urlParse } from "url";
import {
join as pathJoin,
sep as pathSep,
relative as pathRelative,
resolve as pathResolve,
dirname as pathDirname
} from "path";
2024-05-16 08:23:37 +02:00
import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath";
import type { CliCommandOptions } from "../main";
import { z } from "zod";
import * as fs from "fs";
import { assert, type Equals } from "tsafe/assert";
2024-05-16 08:23:37 +02:00
import * as child_process from "child_process";
import {
2024-07-13 19:33:59 +02:00
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
2024-09-08 00:06:47 +02:00
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
} from "./constants";
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
import { exclude } from "tsafe";
import { crawl } from "../tools/crawl";
2024-07-13 19:33:59 +02:00
import { THEME_TYPES } from "./constants";
import { objectEntries } from "tsafe/objectEntries";
import { type ThemeType } from "./constants";
import { id } from "tsafe/id";
import chalk from "chalk";
import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
2024-10-04 12:17:08 +02:00
import { is } from "tsafe/is";
2022-08-16 14:41:06 +07:00
2024-06-09 09:15:16 +02:00
export type BuildContext = {
2023-08-21 05:54:17 +02:00
themeVersion: string;
2024-06-10 07:57:12 +02:00
themeNames: [string, ...string[]];
2023-08-21 05:54:17 +02:00
extraThemeProperties: string[] | undefined;
groupId: string;
artifactId: string;
projectDirPath: string;
projectBuildDirPath: string;
2023-08-21 05:54:17 +02:00
/** Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak */
keycloakifyBuildDirPath: string;
2023-09-03 23:26:34 +02:00
publicDirPath: string;
cacheDirPath: string;
2023-08-21 05:54:17 +02:00
/** If your app is hosted under a subpath, it's the case in CRA if you have "homepage": "https://example.com/my-app" in your package.json
* In this case the urlPathname will be "/my-app/" */
urlPathname: string | undefined;
2024-01-30 00:06:17 +01:00
assetsDirPath: string;
fetchOptions: ProxyFetchOptions;
2024-06-06 01:31:00 +02:00
kcContextExclusionsFtlCode: string | undefined;
environmentVariables: { name: string; default: string }[];
themeSrcDirPath: string;
implementedThemeTypes: {
login: { isImplemented: boolean };
email: { isImplemented: boolean };
account:
| { isImplemented: false }
| { isImplemented: true; type: "Single-Page" | "Multi-Page" };
};
packageJsonFilePath: string;
bundler: "vite" | "webpack";
jarTargets: {
keycloakVersionRange: KeycloakVersionRange;
jarFileBasename: string;
}[];
startKeycloakOptions: {
dockerImage:
| {
reference: string;
tag: string;
}
| undefined;
dockerExtraArgs: string[];
keycloakExtraArgs: string[];
extensionJars: ({ type: "path"; path: string } | { type: "url"; url: string })[];
realmJsonFilePath: string | undefined;
port: number | undefined;
};
2023-08-21 05:54:17 +02:00
};
2022-08-16 14:41:06 +07:00
assert<Equals<keyof BuildContext["implementedThemeTypes"], ThemeType | "email">>();
2024-06-09 09:15:16 +02:00
export type BuildOptions = {
themeName?: string | string[];
2024-06-16 14:53:18 +02:00
themeVersion?: string;
environmentVariables?: { name: string; default: string }[];
2024-05-16 08:23:37 +02:00
extraThemeProperties?: string[];
artifactId?: string;
groupId?: string;
keycloakifyBuildDirPath?: string;
kcContextExclusionsFtl?: string;
startKeycloakOptions?: {
dockerImage?: string;
dockerExtraArgs?: string[];
keycloakExtraArgs?: string[];
extensionJars?: string[];
realmJsonFilePath?: string;
port?: number;
};
} & BuildOptions.AccountThemeImplAndKeycloakVersionTargets;
2024-05-16 08:23:37 +02:00
export namespace BuildOptions {
export type AccountThemeImplAndKeycloakVersionTargets =
| AccountThemeImplAndKeycloakVersionTargets.MultiPageApp
| AccountThemeImplAndKeycloakVersionTargets.SinglePageAppOrNone;
export namespace AccountThemeImplAndKeycloakVersionTargets {
export type MultiPageApp = {
accountThemeImplementation: "Multi-Page";
keycloakVersionTargets?: Record<
KeycloakVersionRange.WithAccountV1Theme,
string | boolean
>;
};
export type SinglePageAppOrNone = {
accountThemeImplementation: "Single-Page" | "none";
keycloakVersionTargets?: Record<
KeycloakVersionRange.WithoutAccountV1Theme,
string | boolean
>;
};
}
}
2024-05-16 08:23:37 +02:00
export type ResolvedViteConfig = {
buildDir: string;
publicDir: string;
assetsDir: string;
urlPathname: string | undefined;
2024-06-09 09:15:16 +02:00
buildOptions: BuildOptions;
2024-05-16 08:23:37 +02:00
};
2024-06-09 09:15:16 +02:00
export function getBuildContext(params: {
2024-05-20 15:48:51 +02:00
cliCommandOptions: CliCommandOptions;
2024-06-09 09:15:16 +02:00
}): BuildContext {
const { cliCommandOptions } = params;
const projectDirPath =
cliCommandOptions.projectDirPath !== undefined
? getAbsoluteAndInOsFormatPath({
pathIsh: cliCommandOptions.projectDirPath,
cwd: process.cwd()
})
: process.cwd();
const { themeSrcDirPath } = (() => {
const srcDirPath = pathJoin(projectDirPath, "src");
const themeSrcDirPath: string | undefined = crawl({
dirPath: srcDirPath,
returnedPathsType: "relative to dirPath"
})
.map(fileRelativePath => {
for (const themeSrcDirBasename of ["keycloak-theme", "keycloak_theme"]) {
const split = fileRelativePath.split(themeSrcDirBasename);
if (split.length === 2) {
return pathJoin(srcDirPath, split[0] + themeSrcDirBasename);
}
}
return undefined;
})
.filter(exclude(undefined))[0];
if (themeSrcDirPath !== undefined) {
return { themeSrcDirPath };
}
2024-07-13 19:33:59 +02:00
for (const themeType of [...THEME_TYPES, "email"]) {
if (!fs.existsSync(pathJoin(srcDirPath, themeType))) {
continue;
}
return { themeSrcDirPath: srcDirPath };
}
console.log(
chalk.red(
[
`Can't locate your Keycloak theme source directory in .${pathSep}${pathRelative(process.cwd(), srcDirPath)}`,
`Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option`,
`If you are collocating your Keycloak theme with your app you must have a directory named 'keycloak-theme' or 'keycloak_theme' in your 'src' directory`
].join("\n")
)
);
process.exit(1);
})();
2024-05-16 08:23:37 +02:00
const { resolvedViteConfig } = (() => {
2024-05-20 15:48:51 +02:00
if (
fs
.readdirSync(projectDirPath)
2024-05-20 15:48:51 +02:00
.find(fileBasename => fileBasename.startsWith("vite.config")) ===
undefined
) {
return { resolvedViteConfig: undefined };
2024-05-16 08:23:37 +02:00
}
const output = child_process
.execSync("npx vite", {
cwd: projectDirPath,
2024-05-20 15:48:51 +02:00
env: {
2024-05-16 08:23:37 +02:00
...process.env,
2024-07-13 19:33:59 +02:00
[VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RESOLVE_VITE_CONFIG]: "true"
2024-05-16 08:23:37 +02:00
}
})
.toString("utf8");
2024-05-20 15:48:51 +02:00
assert(
2024-07-13 19:33:59 +02:00
output.includes(VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RESOLVE_VITE_CONFIG),
2024-05-20 15:48:51 +02:00
"Seems like the Keycloakify's Vite plugin is not installed."
);
2024-05-16 08:23:37 +02:00
2024-05-20 15:48:51 +02:00
const resolvedViteConfigStr = output
2024-07-13 19:33:59 +02:00
.split(VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RESOLVE_VITE_CONFIG)
2024-05-20 15:48:51 +02:00
.reverse()[0];
2024-05-16 08:23:37 +02:00
const resolvedViteConfig: ResolvedViteConfig = JSON.parse(resolvedViteConfigStr);
return { resolvedViteConfig };
})();
const packageJsonFilePath = (function getPackageJSonDirPath(upCount: number): string {
const dirPath = pathResolve(
pathJoin(...[projectDirPath, ...Array(upCount).fill("..")])
);
assert(dirPath !== pathSep, "Root package.json not found");
success: {
const packageJsonFilePath = pathJoin(dirPath, "package.json");
if (!fs.existsSync(packageJsonFilePath)) {
break success;
}
const parsedPackageJson = z
.object({
2024-06-23 22:39:29 +02:00
name: z.string().optional(),
dependencies: z.record(z.string()).optional(),
devDependencies: z.record(z.string()).optional()
})
.parse(JSON.parse(fs.readFileSync(packageJsonFilePath).toString("utf8")));
if (
parsedPackageJson.dependencies?.keycloakify === undefined &&
2024-09-28 00:17:17 +02:00
parsedPackageJson.devDependencies?.keycloakify === undefined
) {
break success;
}
return packageJsonFilePath;
}
return getPackageJSonDirPath(upCount + 1);
})(0);
2024-05-16 08:23:37 +02:00
const parsedPackageJson = (() => {
type BuildOptions_packageJson = BuildOptions & {
2024-06-13 22:58:32 +02:00
projectBuildDirPath?: string;
2024-06-16 14:53:18 +02:00
staticDirPathInProjectBuildDirPath?: string;
2024-06-16 14:58:51 +02:00
publicDirPath?: string;
2024-06-13 22:58:32 +02:00
};
2024-05-16 08:23:37 +02:00
type ParsedPackageJson = {
name?: string;
2024-05-16 08:23:37 +02:00
version?: string;
homepage?: string;
keycloakify?: BuildOptions_packageJson;
2024-05-16 08:23:37 +02:00
};
const zMultiPageApp = (() => {
type TargetType =
BuildOptions.AccountThemeImplAndKeycloakVersionTargets.MultiPageApp;
const zTargetType = z.object({
accountThemeImplementation: z.literal("Multi-Page"),
keycloakVersionTargets: z
.object({
"21-and-below": z.union([z.boolean(), z.string()]),
"23": z.union([z.boolean(), z.string()]),
"24": z.union([z.boolean(), z.string()]),
"25-and-above": z.union([z.boolean(), z.string()])
})
.optional()
});
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zSinglePageApp = (() => {
type TargetType =
BuildOptions.AccountThemeImplAndKeycloakVersionTargets.SinglePageAppOrNone;
const zTargetType = z.object({
accountThemeImplementation: z.union([
z.literal("Single-Page"),
z.literal("none")
]),
keycloakVersionTargets: z
.object({
2024-10-04 12:17:08 +02:00
"22-to-25": z.union([z.boolean(), z.string()]),
"all-other-versions": z.union([z.boolean(), z.string()])
})
.optional()
});
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zAccountThemeImplAndKeycloakVersionTargets = (() => {
type TargetType = BuildOptions.AccountThemeImplAndKeycloakVersionTargets;
2024-05-16 08:23:37 +02:00
const zTargetType = z.union([zMultiPageApp, zSinglePageApp]);
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zStartKeycloakOptions = (() => {
type TargetType = NonNullable<BuildOptions["startKeycloakOptions"]>;
const zTargetType = z.object({
dockerImage: z.string().optional(),
extensionJars: z.array(z.string()).optional(),
realmJsonFilePath: z.string().optional(),
dockerExtraArgs: z.array(z.string()).optional(),
keycloakExtraArgs: z.array(z.string()).optional(),
port: z.number().optional()
});
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zBuildOptions = (() => {
type TargetType = BuildOptions;
const zTargetType = z.intersection(
z.object({
themeName: z.union([z.string(), z.array(z.string())]).optional(),
themeVersion: z.string().optional(),
environmentVariables: z
.array(
z.object({
name: z.string(),
default: z.string()
})
)
.optional(),
extraThemeProperties: z.array(z.string()).optional(),
artifactId: z.string().optional(),
groupId: z.string().optional(),
keycloakifyBuildDirPath: z.string().optional(),
kcContextExclusionsFtl: z.string().optional(),
startKeycloakOptions: zStartKeycloakOptions.optional()
}),
zAccountThemeImplAndKeycloakVersionTargets
);
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zBuildOptions_packageJson = (() => {
type TargetType = BuildOptions_packageJson;
const zTargetType = z.intersection(
zBuildOptions,
z.object({
projectBuildDirPath: z.string().optional(),
staticDirPathInProjectBuildDirPath: z.string().optional(),
publicDirPath: z.string().optional()
})
);
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
const zParsedPackageJson = (() => {
type TargetType = ParsedPackageJson;
const zTargetType = z.object({
name: z.string().optional(),
version: z.string().optional(),
homepage: z.string().optional(),
keycloakify: zBuildOptions_packageJson.optional()
});
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
return id<z.ZodType<TargetType>>(zTargetType);
})();
2024-05-16 08:23:37 +02:00
const configurationPackageJsonFilePath = (() => {
const rootPackageJsonFilePath = pathJoin(projectDirPath, "package.json");
return fs.existsSync(rootPackageJsonFilePath)
? rootPackageJsonFilePath
: packageJsonFilePath;
})();
2024-05-20 15:48:51 +02:00
return zParsedPackageJson.parse(
JSON.parse(fs.readFileSync(configurationPackageJsonFilePath).toString("utf8"))
2024-05-20 15:48:51 +02:00
);
2024-05-16 08:23:37 +02:00
})();
const bundler = resolvedViteConfig !== undefined ? "vite" : "webpack";
if (bundler === "vite" && parsedPackageJson.keycloakify !== undefined) {
console.error(
chalk.red(
`In vite projects, provide your Keycloakify options in vite.config.ts, not in package.json`
)
);
process.exit(-1);
}
const buildOptions: BuildOptions = (() => {
switch (bundler) {
case "vite":
assert(resolvedViteConfig !== undefined);
return resolvedViteConfig.buildOptions;
case "webpack":
assert(parsedPackageJson.keycloakify !== undefined);
return parsedPackageJson.keycloakify;
}
assert<Equals<typeof bundler, never>>(false);
})();
const implementedThemeTypes: BuildContext["implementedThemeTypes"] = {
login: {
isImplemented: fs.existsSync(pathJoin(themeSrcDirPath, "login"))
},
email: {
isImplemented: fs.existsSync(pathJoin(themeSrcDirPath, "email"))
},
account: (() => {
if (buildOptions.accountThemeImplementation === "none") {
return { isImplemented: false };
}
return {
isImplemented: true,
type: buildOptions.accountThemeImplementation
};
})()
};
2022-08-16 14:41:06 +07:00
if (
implementedThemeTypes.account.isImplemented &&
!fs.existsSync(pathJoin(themeSrcDirPath, "account"))
) {
console.error(
chalk.red(
[
`You have set 'accountThemeImplementation' to '${implementedThemeTypes.account.type}'`,
`but the 'account' directory is missing in your theme source directory`,
"Use the `npx keycloakify initialize-account-theme` command to create it"
].join(" ")
)
);
process.exit(-1);
}
2024-06-10 07:57:12 +02:00
const themeNames = ((): [string, ...string[]] => {
const themeNames = ((): [string, ...string[]] => {
if (buildOptions.themeName === undefined) {
return parsedPackageJson.name === undefined
? ["keycloakify"]
: [
parsedPackageJson.name
.replace(/^@(.*)/, "$1")
.split("/")
.join("-")
];
}
2022-08-16 14:41:06 +07:00
if (typeof buildOptions.themeName === "string") {
return [buildOptions.themeName];
}
const [mainThemeName, ...themeVariantNames] = buildOptions.themeName;
assert(mainThemeName !== undefined);
2024-06-10 07:57:12 +02:00
return [mainThemeName, ...themeVariantNames];
})();
for (const themeName of themeNames) {
if (!/^[a-zA-Z0-9_-]+$/.test(themeName)) {
console.error(
chalk.red(
[
`Invalid theme name: ${themeName}`,
`Theme names should only contain letters, numbers, and "_" or "-"`
].join(" ")
)
);
process.exit(-1);
}
}
2024-06-10 07:57:12 +02:00
return themeNames;
})();
2022-08-16 14:41:06 +07:00
const projectBuildDirPath = (() => {
2024-01-30 06:55:26 +01:00
webpack: {
if (bundler !== "webpack") {
2024-01-30 06:55:26 +01:00
break webpack;
}
assert(parsedPackageJson.keycloakify !== undefined);
if (parsedPackageJson.keycloakify.projectBuildDirPath !== undefined) {
2024-01-30 06:55:26 +01:00
return getAbsoluteAndInOsFormatPath({
pathIsh: parsedPackageJson.keycloakify.projectBuildDirPath,
cwd: projectDirPath
2024-01-30 06:55:26 +01:00
});
}
return pathJoin(projectDirPath, "build");
2024-01-30 06:55:26 +01:00
}
assert(bundler === "vite");
assert(resolvedViteConfig !== undefined);
return pathJoin(projectDirPath, resolvedViteConfig.buildDir);
2024-01-30 06:55:26 +01:00
})();
2024-01-30 05:54:36 +01:00
return {
bundler,
packageJsonFilePath,
2024-06-16 14:53:18 +02:00
themeVersion: buildOptions.themeVersion ?? parsedPackageJson.version ?? "0.0.0",
themeNames,
2024-06-09 09:15:16 +02:00
extraThemeProperties: buildOptions.extraThemeProperties,
2024-05-20 15:48:51 +02:00
groupId: (() => {
const fallbackGroupId = `${themeNames[0]}.keycloak`;
2023-08-21 05:54:17 +02:00
return (
process.env.KEYCLOAKIFY_GROUP_ID ??
2024-06-09 09:15:16 +02:00
buildOptions.groupId ??
2024-01-30 05:54:36 +01:00
(parsedPackageJson.homepage === undefined
2023-08-21 05:54:17 +02:00
? fallbackGroupId
2024-01-30 05:54:36 +01:00
: urlParse(parsedPackageJson.homepage)
2023-08-21 05:54:17 +02:00
.host?.replace(/:[0-9]+$/, "")
?.split(".")
.reverse()
.join(".") ?? fallbackGroupId) + ".keycloak"
);
})(),
2024-05-20 15:48:51 +02:00
artifactId:
process.env.KEYCLOAKIFY_ARTIFACT_ID ??
2024-06-09 09:15:16 +02:00
buildOptions.artifactId ??
2024-05-20 15:48:51 +02:00
`${themeNames[0]}-keycloak-theme`,
projectDirPath,
projectBuildDirPath,
2024-05-20 15:48:51 +02:00
keycloakifyBuildDirPath: (() => {
2024-06-09 09:15:16 +02:00
if (buildOptions.keycloakifyBuildDirPath !== undefined) {
return getAbsoluteAndInOsFormatPath({
2024-06-09 09:15:16 +02:00
pathIsh: buildOptions.keycloakifyBuildDirPath,
cwd: projectDirPath
});
}
return pathJoin(
projectDirPath,
2024-05-20 15:48:51 +02:00
resolvedViteConfig?.buildDir === undefined
? "build_keycloak"
: `${resolvedViteConfig.buildDir}_keycloak`
);
})(),
2024-05-20 15:48:51 +02:00
publicDirPath: (() => {
2024-06-16 14:58:51 +02:00
if (process.env.PUBLIC_DIR_PATH !== undefined) {
return getAbsoluteAndInOsFormatPath({
pathIsh: process.env.PUBLIC_DIR_PATH,
cwd: projectDirPath
});
}
2024-01-30 06:55:26 +01:00
webpack: {
if (bundler !== "webpack") {
2024-01-30 06:55:26 +01:00
break webpack;
}
2024-01-27 18:49:29 +01:00
assert(parsedPackageJson.keycloakify !== undefined);
if (parsedPackageJson.keycloakify.publicDirPath !== undefined) {
2024-01-30 06:55:26 +01:00
return getAbsoluteAndInOsFormatPath({
pathIsh: parsedPackageJson.keycloakify.publicDirPath,
cwd: projectDirPath
2024-01-30 06:55:26 +01:00
});
}
return pathJoin(projectDirPath, "public");
2023-08-21 05:54:17 +02:00
}
2022-08-16 14:41:06 +07:00
assert(bundler === "vite");
assert(resolvedViteConfig !== undefined);
return pathJoin(projectDirPath, resolvedViteConfig.publicDir);
2023-08-21 05:54:17 +02:00
})(),
2024-07-27 00:44:32 +02:00
cacheDirPath: pathJoin(
(() => {
if (process.env.XDG_CACHE_HOME !== undefined) {
return getAbsoluteAndInOsFormatPath({
pathIsh: process.env.XDG_CACHE_HOME,
cwd: process.cwd()
});
}
2024-07-27 00:44:32 +02:00
return pathJoin(
pathDirname(packageJsonFilePath),
"node_modules",
".cache"
);
})(),
"keycloakify"
),
2024-05-20 15:48:51 +02:00
urlPathname: (() => {
2024-01-30 06:55:26 +01:00
webpack: {
if (bundler !== "webpack") {
2024-01-30 06:55:26 +01:00
break webpack;
}
const { homepage } = parsedPackageJson;
let url: URL | undefined = undefined;
2022-08-16 14:41:06 +07:00
2024-01-30 06:55:26 +01:00
if (homepage !== undefined) {
url = new URL(homepage);
}
if (url === undefined) {
return undefined;
}
2022-08-16 14:41:06 +07:00
2024-01-30 06:55:26 +01:00
const out = url.pathname.replace(/([^/])$/, "$1/");
return out === "/" ? undefined : out;
2023-08-21 05:54:17 +02:00
}
2022-08-16 14:41:06 +07:00
assert(bundler === "vite");
assert(resolvedViteConfig !== undefined);
2024-01-30 06:55:26 +01:00
return resolvedViteConfig.urlPathname;
})(),
2024-05-20 15:48:51 +02:00
assetsDirPath: (() => {
2024-01-30 06:55:26 +01:00
webpack: {
if (bundler !== "webpack") {
2024-01-30 06:55:26 +01:00
break webpack;
}
assert(parsedPackageJson.keycloakify !== undefined);
if (
parsedPackageJson.keycloakify.staticDirPathInProjectBuildDirPath !==
undefined
) {
getAbsoluteAndInOsFormatPath({
pathIsh:
parsedPackageJson.keycloakify
.staticDirPathInProjectBuildDirPath,
cwd: projectBuildDirPath
});
}
return pathJoin(projectBuildDirPath, "static");
2023-08-21 05:54:17 +02:00
}
assert(bundler === "vite");
assert(resolvedViteConfig !== undefined);
2022-08-16 14:41:06 +07:00
return pathJoin(projectBuildDirPath, resolvedViteConfig.assetsDir);
})(),
kcContextExclusionsFtlCode: (() => {
if (buildOptions.kcContextExclusionsFtl === undefined) {
return undefined;
}
if (buildOptions.kcContextExclusionsFtl.endsWith(".ftl")) {
const kcContextExclusionsFtlPath = getAbsoluteAndInOsFormatPath({
pathIsh: buildOptions.kcContextExclusionsFtl,
cwd: projectDirPath
});
return fs.readFileSync(kcContextExclusionsFtlPath).toString("utf8");
}
return buildOptions.kcContextExclusionsFtl;
})(),
environmentVariables: buildOptions.environmentVariables ?? [],
implementedThemeTypes,
themeSrcDirPath,
fetchOptions: getProxyFetchOptions({
npmConfigGetCwd: (function callee(upCount: number): string {
const dirPath = pathResolve(
pathJoin(...[projectDirPath, ...Array(upCount).fill("..")])
);
assert(
dirPath !== pathSep,
"Couldn't find a place to run 'npm config get'"
);
try {
child_process.execSync("npm config get", {
cwd: dirPath,
2024-07-09 14:59:59 +02:00
stdio: "pipe"
});
} catch (error) {
if (String(error).includes("ENOWORKSPACES")) {
return callee(upCount + 1);
}
throw error;
}
return dirPath;
})(0)
}),
jarTargets: (() => {
const getDefaultJarFileBasename = (range: string) =>
`keycloak-theme-for-kc-${range}.jar`;
build_for_specific_keycloak_major_version: {
const buildForKeycloakMajorVersionNumber = (() => {
2024-07-13 19:33:59 +02:00
const envValue =
process.env[BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME];
if (envValue === undefined) {
return undefined;
}
const major = parseInt(envValue);
assert(!isNaN(major));
return major;
})();
if (buildForKeycloakMajorVersionNumber === undefined) {
break build_for_specific_keycloak_major_version;
}
const keycloakVersionRange: KeycloakVersionRange = (() => {
if (
implementedThemeTypes.account.isImplemented &&
implementedThemeTypes.account.type === "Multi-Page"
) {
const keycloakVersionRange = (() => {
if (buildForKeycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
}
assert(buildForKeycloakMajorVersionNumber !== 22);
if (buildForKeycloakMajorVersionNumber === 23) {
return "23" as const;
}
if (buildForKeycloakMajorVersionNumber === 24) {
return "24" as const;
}
return "25-and-above" as const;
})();
assert<
Equals<
typeof keycloakVersionRange,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange.WithAccountV1Theme
>
>();
return keycloakVersionRange;
} else {
const keycloakVersionRange = (() => {
2024-10-04 12:17:08 +02:00
if (
buildForKeycloakMajorVersionNumber <= 21 ||
buildForKeycloakMajorVersionNumber >= 26
) {
return "all-other-versions" as const;
}
2024-10-04 12:17:08 +02:00
return "22-to-25" as const;
})();
assert<
Equals<
typeof keycloakVersionRange,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange.WithoutAccountV1Theme
>
>();
return keycloakVersionRange;
}
})();
const jarFileBasename = (() => {
use_custom_jar_basename: {
const { keycloakVersionTargets } = buildOptions;
2024-10-04 12:17:08 +02:00
assert(
is<Record<KeycloakVersionRange, string | boolean>>(
keycloakVersionTargets
)
);
if (keycloakVersionTargets === undefined) {
break use_custom_jar_basename;
}
const entry = objectEntries(keycloakVersionTargets).find(
([keycloakVersionRange_entry]) =>
keycloakVersionRange_entry === keycloakVersionRange
);
if (entry === undefined) {
break use_custom_jar_basename;
}
const maybeJarFileBasename = entry[1];
if (typeof maybeJarFileBasename !== "string") {
break use_custom_jar_basename;
}
return maybeJarFileBasename;
}
return getDefaultJarFileBasename(keycloakVersionRange);
})();
return [
{
keycloakVersionRange,
jarFileBasename
}
];
}
const jarTargets_default = (() => {
const jarTargets: BuildContext["jarTargets"] = [];
if (
implementedThemeTypes.account.isImplemented &&
implementedThemeTypes.account.type === "Multi-Page"
) {
for (const keycloakVersionRange of [
"21-and-below",
"23",
"24",
"25-and-above"
] as const) {
assert<
Equals<
typeof keycloakVersionRange,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange.WithAccountV1Theme
>
>(true);
jarTargets.push({
keycloakVersionRange,
jarFileBasename:
getDefaultJarFileBasename(keycloakVersionRange)
});
}
} else {
for (const keycloakVersionRange of [
2024-10-04 12:17:08 +02:00
"22-to-25",
"all-other-versions"
] as const) {
assert<
Equals<
typeof keycloakVersionRange,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange.WithoutAccountV1Theme
>
>(true);
jarTargets.push({
keycloakVersionRange,
jarFileBasename:
getDefaultJarFileBasename(keycloakVersionRange)
});
}
}
return jarTargets;
})();
if (buildOptions.keycloakVersionTargets === undefined) {
return jarTargets_default;
}
const jarTargets: BuildContext["jarTargets"] = [];
for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(
2024-10-04 12:17:08 +02:00
(() => {
const { keycloakVersionTargets } = buildOptions;
assert(
is<Record<KeycloakVersionRange, string | boolean>>(
keycloakVersionTargets
)
);
return keycloakVersionTargets;
})()
)) {
if (jarNameOrBoolean === false) {
continue;
}
if (jarNameOrBoolean === true) {
jarTargets.push({
keycloakVersionRange: keycloakVersionRange,
jarFileBasename: getDefaultJarFileBasename(keycloakVersionRange)
});
continue;
}
const jarFileBasename = jarNameOrBoolean;
if (!jarFileBasename.endsWith(".jar")) {
console.log(
chalk.red(`Bad ${jarFileBasename} should end with '.jar'\n`)
);
process.exit(1);
}
if (jarFileBasename.includes("/") || jarFileBasename.includes("\\")) {
console.log(
chalk.red(
[
`Invalid ${jarFileBasename}. It's not supposed to be a path,`,
`Only the basename of the jar file is expected.`,
`Example: keycloak-theme.jar`
].join(" ")
)
);
process.exit(1);
}
jarTargets.push({
keycloakVersionRange: keycloakVersionRange,
jarFileBasename: jarNameOrBoolean
});
}
if (jarTargets.length === 0) {
console.log(
chalk.red(
"All jar targets are disabled. Please enable at least one jar target."
)
);
process.exit(1);
}
return jarTargets;
})(),
startKeycloakOptions: {
dockerImage: (() => {
if (buildOptions.startKeycloakOptions?.dockerImage === undefined) {
return undefined;
}
const [reference, tag, ...rest] =
buildOptions.startKeycloakOptions.dockerImage.split(":");
assert(
reference !== undefined && tag !== undefined && rest.length === 0,
`Invalid docker image: ${buildOptions.startKeycloakOptions.dockerImage}`
);
return { reference, tag };
})(),
dockerExtraArgs: buildOptions.startKeycloakOptions?.dockerExtraArgs ?? [],
keycloakExtraArgs: buildOptions.startKeycloakOptions?.keycloakExtraArgs ?? [],
extensionJars: (buildOptions.startKeycloakOptions?.extensionJars ?? []).map(
urlOrPath => {
if (/^https?:\/\//.test(urlOrPath)) {
return { type: "url", url: urlOrPath };
}
return {
type: "path",
path: getAbsoluteAndInOsFormatPath({
pathIsh: urlOrPath,
cwd: projectDirPath
})
};
}
),
realmJsonFilePath:
buildOptions.startKeycloakOptions?.realmJsonFilePath === undefined
? undefined
: getAbsoluteAndInOsFormatPath({
pathIsh: buildOptions.startKeycloakOptions.realmJsonFilePath,
cwd: projectDirPath
}),
port: buildOptions.startKeycloakOptions?.port
}
2023-08-21 05:54:17 +02:00
};
2022-08-16 14:41:06 +07:00
}