Update prettier configuration
This commit is contained in:
@ -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<void> {
|
||||
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<typeof transformCodebase>["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<typeof transformCodebase>["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<void>((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 });
|
||||
}
|
||||
|
@ -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<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
export async function buildJars(params: { buildOptions: BuildOptionsLike }): Promise<void> {
|
||||
export async function buildJars(params: {
|
||||
buildOptions: BuildOptionsLike;
|
||||
}): Promise<void> {
|
||||
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()
|
||||
|
@ -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];
|
||||
|
@ -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: {
|
||||
` <properties>`,
|
||||
` <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>`,
|
||||
` </properties>`,
|
||||
...(keycloakAccountV1Version !== null && keycloakThemeAdditionalInfoExtensionVersion !== null
|
||||
...(keycloakAccountV1Version !== null &&
|
||||
keycloakThemeAdditionalInfoExtensionVersion !== null
|
||||
? [
|
||||
` <build>`,
|
||||
` <plugins>`,
|
||||
|
@ -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<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||
assert<
|
||||
Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>
|
||||
>(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<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||
assert<
|
||||
Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>
|
||||
>(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<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||
assert<
|
||||
Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>
|
||||
>(false);
|
||||
}
|
||||
})();
|
||||
|
||||
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme | undefined>>();
|
||||
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<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(
|
||||
false
|
||||
);
|
||||
})();
|
||||
|
||||
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithoutAccountTheme | undefined>>();
|
||||
assert<
|
||||
Equals<
|
||||
typeof keycloakVersionRange,
|
||||
KeycloakVersionRange.WithoutAccountTheme | undefined
|
||||
>
|
||||
>();
|
||||
|
||||
return keycloakVersionRange;
|
||||
}
|
||||
|
@ -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(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1]
|
||||
.replace("FIELD_NAMES_eKsIY4ZsZ4xeM", fieldNames.map(name => `"${name}"`).join(", "))
|
||||
.replace(
|
||||
"FIELD_NAMES_eKsIY4ZsZ4xeM",
|
||||
fieldNames.map(name => `"${name}"`).join(", ")
|
||||
)
|
||||
.replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion)
|
||||
.replace("KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx", buildOptions.themeVersion)
|
||||
.replace("KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr", themeType)
|
||||
.replace("KEYCLOAKIFY_THEME_NAME_cXxKd3xEer", themeName)
|
||||
.replace("RESOURCES_COMMON_cLsLsMrtDkpVv", resources_common);
|
||||
|
||||
const ftlObjectToJsCodeDeclaringAnObjectPlaceholder = '{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }';
|
||||
const ftlObjectToJsCodeDeclaringAnObjectPlaceholder =
|
||||
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }';
|
||||
|
||||
$("head").prepend(`<script>\nwindow.${nameOfTheGlobal}=${ftlObjectToJsCodeDeclaringAnObjectPlaceholder}</script>`);
|
||||
$("head").prepend(
|
||||
`<script>\nwindow.${nameOfTheGlobal}=${ftlObjectToJsCodeDeclaringAnObjectPlaceholder}</script>`
|
||||
);
|
||||
|
||||
// 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 };
|
||||
}
|
||||
|
@ -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<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
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(" "),
|
||||
"",
|
||||
|
@ -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<string, string> } = {};
|
||||
let extraMessages: {
|
||||
[languageTag: string]: Record<string, string>;
|
||||
} = {};
|
||||
|
||||
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")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ export type BuildOptionsLike = BuildOptionsLike_generateSrcMainResourcesForMainT
|
||||
|
||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
export async function generateSrcMainResources(params: { buildOptions: BuildOptionsLike }): Promise<void> {
|
||||
export async function generateSrcMainResources(params: {
|
||||
buildOptions: BuildOptionsLike;
|
||||
}): Promise<void> {
|
||||
const { buildOptions } = params;
|
||||
|
||||
const [themeName, ...themeVariantNames] = buildOptions.themeNames;
|
||||
|
@ -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<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
export async function generateSrcMainResourcesForMainTheme(params: { themeName: string; buildOptions: BuildOptionsLike }): Promise<void> {
|
||||
export async function generateSrcMainResourcesForMainTheme(params: {
|
||||
themeName: string;
|
||||
buildOptions: BuildOptionsLike;
|
||||
}): Promise<void> {
|
||||
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<string, string> = {};
|
||||
|
||||
const implementedThemeTypes: Record<ThemeType | "email", boolean> = {
|
||||
"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
|
||||
});
|
||||
}
|
||||
|
@ -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<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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<string>()).filter(pageId => {
|
||||
|
@ -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<string>();
|
||||
|
||||
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()
|
||||
|
@ -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 }
|
||||
);
|
||||
}
|
||||
|
@ -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`)
|
||||
);
|
||||
}
|
||||
|
@ -18,7 +18,15 @@ export function replaceImportsInCssCode(params: { cssCode: string }): {
|
||||
const cssGlobalsToDefine: Record<string, string> = {};
|
||||
|
||||
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<string, string>; buildOptions: BuildOptionsLike }): {
|
||||
export function generateCssCodeToDefineGlobals(params: {
|
||||
cssGlobalsToDefine: Record<string, string>;
|
||||
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(" ")
|
||||
|
@ -8,7 +8,10 @@ export type BuildOptionsLike = {
|
||||
|
||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
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 };
|
||||
|
@ -13,7 +13,10 @@ export type BuildOptionsLike = {
|
||||
|
||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
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":
|
||||
|
@ -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;
|
||||
|
@ -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<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
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<typeof String.prototype.replace> => [
|
||||
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<typeof String.prototype.replace> => [
|
||||
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}`
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user