Fix some errors implementing the new account SPA feature
This commit is contained in:
parent
488dd2c6b9
commit
c87b6153bb
@ -37,10 +37,10 @@ import {
|
|||||||
} from "../../shared/metaInfKeycloakThemes";
|
} from "../../shared/metaInfKeycloakThemes";
|
||||||
import { objectEntries } from "tsafe/objectEntries";
|
import { objectEntries } from "tsafe/objectEntries";
|
||||||
import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
|
import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
|
||||||
import * as child_process from "child_process";
|
|
||||||
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
||||||
import propertiesParser from "properties-parser";
|
import propertiesParser from "properties-parser";
|
||||||
import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed";
|
import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed";
|
||||||
|
import { listInstalledModules } from "../../tools/listInstalledModules";
|
||||||
|
|
||||||
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
||||||
BuildContextLike_generateMessageProperties & {
|
BuildContextLike_generateMessageProperties & {
|
||||||
@ -238,9 +238,9 @@ export async function generateResources(params: {
|
|||||||
|
|
||||||
let languageTags: string[] | undefined = undefined;
|
let languageTags: string[] | undefined = undefined;
|
||||||
|
|
||||||
i18n_messages_generation: {
|
i18n_multi_page: {
|
||||||
if (isSpa) {
|
if (isSpa) {
|
||||||
break i18n_messages_generation;
|
break i18n_multi_page;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(themeType !== "admin");
|
assert(themeType !== "admin");
|
||||||
@ -257,23 +257,43 @@ export async function generateResources(params: {
|
|||||||
writeMessagePropertiesFiles;
|
writeMessagePropertiesFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
bring_in_account_spa_messages: {
|
let isLegacyAccountSpa = false;
|
||||||
|
|
||||||
|
// NOTE: Eventually remove this block.
|
||||||
|
i18n_single_page_account_legacy: {
|
||||||
if (!isSpa) {
|
if (!isSpa) {
|
||||||
break bring_in_account_spa_messages;
|
break i18n_single_page_account_legacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (themeType !== "account") {
|
if (themeType !== "account") {
|
||||||
break bring_in_account_spa_messages;
|
break i18n_single_page_account_legacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountUiDirPath = child_process
|
const [moduleMeta] = await listInstalledModules({
|
||||||
.execSync(`npm list @keycloakify/keycloak-account-ui --parseable`, {
|
packageJsonFilePath: buildContext.packageJsonFilePath,
|
||||||
cwd: pathDirname(buildContext.packageJsonFilePath)
|
filter: ({ moduleName }) =>
|
||||||
})
|
moduleName === "@keycloakify/keycloak-account-ui"
|
||||||
.toString("utf8")
|
});
|
||||||
.trim();
|
|
||||||
|
|
||||||
const messageDirPath_defaults = pathJoin(accountUiDirPath, "messages");
|
assert(
|
||||||
|
moduleMeta !== undefined,
|
||||||
|
`@keycloakify/keycloak-account-ui is supposed to be installed`
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
const [majorStr] = moduleMeta.version.split(".");
|
||||||
|
|
||||||
|
if (majorStr.length === 6) {
|
||||||
|
// NOTE: Now we use the format MMmmpp (Major, minor, patch) for example for
|
||||||
|
// 26.0.7 it would be 260007.
|
||||||
|
break i18n_single_page_account_legacy;
|
||||||
|
} else {
|
||||||
|
// 25.0.4-rc.5 or later
|
||||||
|
isLegacyAccountSpa = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageDirPath_defaults = pathJoin(moduleMeta.dirPath, "messages");
|
||||||
|
|
||||||
if (!fs.existsSync(messageDirPath_defaults)) {
|
if (!fs.existsSync(messageDirPath_defaults)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -281,6 +301,8 @@ export async function generateResources(params: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLegacyAccountSpa = true;
|
||||||
|
|
||||||
const messagesDirPath_dest = pathJoin(
|
const messagesDirPath_dest = pathJoin(
|
||||||
getThemeTypeDirPath({ themeName, themeType: "account" }),
|
getThemeTypeDirPath({ themeName, themeType: "account" }),
|
||||||
"messages"
|
"messages"
|
||||||
@ -342,14 +364,20 @@ export async function generateResources(params: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bring_in_admin_messages: {
|
i18n_single_page: {
|
||||||
if (themeType !== "admin") {
|
if (!isSpa) {
|
||||||
break bring_in_admin_messages;
|
break i18n_single_page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLegacyAccountSpa) {
|
||||||
|
break i18n_single_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(themeType === "account" || themeType === "admin");
|
||||||
|
|
||||||
const messagesDirPath_theme = pathJoin(
|
const messagesDirPath_theme = pathJoin(
|
||||||
buildContext.themeSrcDirPath,
|
buildContext.themeSrcDirPath,
|
||||||
"admin",
|
themeType,
|
||||||
"i18n"
|
"i18n"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -423,7 +451,7 @@ export async function generateResources(params: {
|
|||||||
|
|
||||||
propertiesByLang[parsedBasename.lang] ??= {
|
propertiesByLang[parsedBasename.lang] ??= {
|
||||||
base: createObjectThatThrowsIfAccessed<Buffer>({
|
base: createObjectThatThrowsIfAccessed<Buffer>({
|
||||||
debugMessage: `No base ${parsedBasename.lang} translation for admin theme`
|
debugMessage: `No base ${parsedBasename.lang} translation for ${themeType} theme`
|
||||||
}),
|
}),
|
||||||
override: undefined,
|
override: undefined,
|
||||||
overrideByThemeName: {}
|
overrideByThemeName: {}
|
||||||
@ -446,7 +474,9 @@ export async function generateResources(params: {
|
|||||||
] = buffer;
|
] = buffer;
|
||||||
});
|
});
|
||||||
|
|
||||||
writeMessagePropertiesFilesByThemeType.admin = ({
|
languageTags = Object.keys(propertiesByLang);
|
||||||
|
|
||||||
|
writeMessagePropertiesFilesByThemeType[themeType] = ({
|
||||||
messageDirPath,
|
messageDirPath,
|
||||||
themeName
|
themeName
|
||||||
}) => {
|
}) => {
|
||||||
@ -456,8 +486,6 @@ export async function generateResources(params: {
|
|||||||
|
|
||||||
Object.entries(propertiesByLang).forEach(
|
Object.entries(propertiesByLang).forEach(
|
||||||
([lang, { base, override, overrideByThemeName }]) => {
|
([lang, { base, override, overrideByThemeName }]) => {
|
||||||
(languageTags ??= []).push(lang);
|
|
||||||
|
|
||||||
const messages = propertiesParser.parse(base.toString("utf8"));
|
const messages = propertiesParser.parse(base.toString("utf8"));
|
||||||
|
|
||||||
if (override !== undefined) {
|
if (override !== undefined) {
|
||||||
|
@ -124,8 +124,7 @@ async function command_own(params: Params_subcommands) {
|
|||||||
] of targetFileRelativePathsByExtensionModuleMeta.entries()) {
|
] of targetFileRelativePathsByExtensionModuleMeta.entries()) {
|
||||||
const extensionModuleDirPath = await getInstalledModuleDirPath({
|
const extensionModuleDirPath = await getInstalledModuleDirPath({
|
||||||
moduleName: extensionModuleMeta.moduleName,
|
moduleName: extensionModuleMeta.moduleName,
|
||||||
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath),
|
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
||||||
projectDirPath: buildContext.projectDirPath
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const fileRelativePath of fileRelativePaths) {
|
for (const fileRelativePath of fileRelativePaths) {
|
||||||
|
@ -109,7 +109,6 @@ export async function getExtensionModuleMetas(params: {
|
|||||||
const installedExtensionModules = await (async () => {
|
const installedExtensionModules = await (async () => {
|
||||||
const installedModulesWithKeycloakifyInTheName = await listInstalledModules({
|
const installedModulesWithKeycloakifyInTheName = await listInstalledModules({
|
||||||
packageJsonFilePath: buildContext.packageJsonFilePath,
|
packageJsonFilePath: buildContext.packageJsonFilePath,
|
||||||
projectDirPath: buildContext.packageJsonFilePath,
|
|
||||||
filter: ({ moduleName }) =>
|
filter: ({ moduleName }) =>
|
||||||
moduleName.includes("keycloakify") && moduleName !== "keycloakify"
|
moduleName.includes("keycloakify") && moduleName !== "keycloakify"
|
||||||
});
|
});
|
||||||
|
@ -2,40 +2,42 @@ import { join as pathJoin } from "path";
|
|||||||
import { existsAsync } from "./fs.existsAsync";
|
import { existsAsync } from "./fs.existsAsync";
|
||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
|
import { getIsRootPath } from "../tools/isRootPath";
|
||||||
|
|
||||||
export async function getInstalledModuleDirPath(params: {
|
export async function getInstalledModuleDirPath(params: {
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
packageJsonDirPath: string;
|
packageJsonDirPath: string;
|
||||||
projectDirPath: string;
|
|
||||||
}) {
|
}) {
|
||||||
const { moduleName, packageJsonDirPath, projectDirPath } = params;
|
const { moduleName, packageJsonDirPath } = params;
|
||||||
|
|
||||||
common_case: {
|
{
|
||||||
const dirPath = pathJoin(
|
let dirPath = packageJsonDirPath;
|
||||||
...[packageJsonDirPath, "node_modules", ...moduleName.split("/")]
|
|
||||||
|
while (true) {
|
||||||
|
const dirPath_candidate = pathJoin(
|
||||||
|
dirPath,
|
||||||
|
"node_modules",
|
||||||
|
...moduleName.split("/")
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!(await existsAsync(dirPath))) {
|
let doesExist: boolean;
|
||||||
break common_case;
|
|
||||||
|
try {
|
||||||
|
doesExist = await existsAsync(dirPath_candidate);
|
||||||
|
} catch {
|
||||||
|
doesExist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirPath;
|
if (doesExist) {
|
||||||
|
return dirPath_candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_modules_at_root_case: {
|
if (getIsRootPath(dirPath)) {
|
||||||
if (projectDirPath === packageJsonDirPath) {
|
break;
|
||||||
break node_modules_at_root_case;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirPath = pathJoin(
|
dirPath = pathJoin(dirPath, "..");
|
||||||
...[projectDirPath, "node_modules", ...moduleName.split("/")]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!(await existsAsync(dirPath))) {
|
|
||||||
break node_modules_at_root_case;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirPath = child_process
|
const dirPath = child_process
|
||||||
|
22
src/bin/tools/isRootPath.ts
Normal file
22
src/bin/tools/isRootPath.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { normalize as pathNormalize } from "path";
|
||||||
|
|
||||||
|
export function getIsRootPath(filePath: string): boolean {
|
||||||
|
const path_normalized = pathNormalize(filePath);
|
||||||
|
|
||||||
|
// Unix-like root ("/")
|
||||||
|
if (path_normalized === "/") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Windows drive root (e.g., "C:\\")
|
||||||
|
if (/^[a-zA-Z]:\\$/.test(path_normalized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for UNC root (e.g., "\\server\share")
|
||||||
|
if (/^\\\\[^\\]+\\[^\\]+\\?$/.test(path_normalized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -8,7 +8,6 @@ import { exclude } from "tsafe/exclude";
|
|||||||
|
|
||||||
export async function listInstalledModules(params: {
|
export async function listInstalledModules(params: {
|
||||||
packageJsonFilePath: string;
|
packageJsonFilePath: string;
|
||||||
projectDirPath: string;
|
|
||||||
filter: (params: { moduleName: string }) => boolean;
|
filter: (params: { moduleName: string }) => boolean;
|
||||||
}): Promise<
|
}): Promise<
|
||||||
{
|
{
|
||||||
@ -18,7 +17,7 @@ export async function listInstalledModules(params: {
|
|||||||
peerDependencies: Record<string, string>;
|
peerDependencies: Record<string, string>;
|
||||||
}[]
|
}[]
|
||||||
> {
|
> {
|
||||||
const { packageJsonFilePath, projectDirPath, filter } = params;
|
const { packageJsonFilePath, filter } = params;
|
||||||
|
|
||||||
const parsedPackageJson = await readPackageJsonDependencies({
|
const parsedPackageJson = await readPackageJsonDependencies({
|
||||||
packageJsonFilePath
|
packageJsonFilePath
|
||||||
@ -36,8 +35,7 @@ export async function listInstalledModules(params: {
|
|||||||
extensionModuleNames.map(async moduleName => {
|
extensionModuleNames.map(async moduleName => {
|
||||||
const dirPath = await getInstalledModuleDirPath({
|
const dirPath = await getInstalledModuleDirPath({
|
||||||
moduleName,
|
moduleName,
|
||||||
packageJsonDirPath: pathDirname(packageJsonFilePath),
|
packageJsonDirPath: pathDirname(packageJsonFilePath)
|
||||||
projectDirPath
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { version, peerDependencies } =
|
const { version, peerDependencies } =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user