keycloak_theme/src/bin/initialize-email-theme.ts

154 lines
4.7 KiB
TypeScript
Raw Normal View History

2024-10-05 20:30:09 +02:00
import type { BuildContext } from "./shared/buildContext";
import cliSelect from "cli-select";
import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
import { exitIfUncommittedChanges } from "./shared/exitIfUncommittedChanges";
import { dirname as pathDirname, join as pathJoin, relative as pathRelative } from "path";
import * as fs from "fs";
import { assert, is, type Equals } from "tsafe/assert";
import { id } from "tsafe/id";
import { addSyncExtensionsToPostinstallScript } from "./shared/addSyncExtensionsToPostinstallScript";
import { getIsPrettierAvailable, runPrettier } from "./tools/runPrettier";
import { npmInstall } from "./tools/npmInstall";
import * as child_process from "child_process";
import { z } from "zod";
import chalk from "chalk";
2023-03-24 05:43:34 +01:00
2024-10-05 20:30:09 +02:00
export async function command(params: { buildContext: BuildContext }) {
const { buildContext } = params;
const { hasBeenHandled } = maybeDelegateCommandToCustomHandler({
commandName: "initialize-account-theme",
buildContext
});
if (hasBeenHandled) {
return;
}
exitIfUncommittedChanges({
projectDirPath: buildContext.projectDirPath
});
const emailThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "email");
2024-09-08 12:00:07 +02:00
if (
fs.existsSync(emailThemeSrcDirPath) &&
fs.readdirSync(emailThemeSrcDirPath).length > 0
) {
2024-05-20 15:48:51 +02:00
console.warn(
chalk.red(
`There is already a ${pathRelative(
process.cwd(),
emailThemeSrcDirPath
)} directory in your project. Aborting.`
)
2024-05-20 15:48:51 +02:00
);
2023-03-20 01:30:42 +01:00
process.exit(-1);
}
const { value: emailThemeType } = await cliSelect({
values: ["native (FreeMarker)" as const, "jsx-email (React)" as const]
}).catch(() => {
process.exit(-1);
});
if (emailThemeType === "jsx-email (React)") {
console.log(
[
"There is currently no automated support for keycloakify-email, it has to be done manually, see documentation:",
"https://docs.keycloakify.dev/theme-types/email-theme"
].join("\n")
);
process.exit(0);
}
const parsedPackageJson = (() => {
type ParsedPackageJson = {
scripts?: Record<string, string | undefined>;
dependencies?: Record<string, string | undefined>;
devDependencies?: Record<string, string | undefined>;
};
const zParsedPackageJson = (() => {
type TargetType = ParsedPackageJson;
const zTargetType = z.object({
scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
});
2024-10-17 23:23:26 +02:00
assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
return id<z.ZodType<TargetType>>(zTargetType);
})();
const parsedPackageJson = JSON.parse(
fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8")
);
2024-10-17 23:23:26 +02:00
zParsedPackageJson.parse(parsedPackageJson);
2024-10-17 23:23:26 +02:00
assert(is<ParsedPackageJson>(parsedPackageJson));
2024-09-08 12:00:07 +02:00
return parsedPackageJson;
})();
2024-09-08 12:00:07 +02:00
addSyncExtensionsToPostinstallScript({
parsedPackageJson,
buildContext
2023-03-20 01:30:42 +01:00
});
const moduleName = `@keycloakify/email-native`;
const [version] = ((): string[] => {
const cmdOutput = child_process
.execSync(`npm show ${moduleName} versions --json`)
.toString("utf8")
.trim();
const versions = JSON.parse(cmdOutput) as string | string[];
// NOTE: Bug in some older npm versions
if (typeof versions === "string") {
return [versions];
}
return versions;
})()
.reverse()
.filter(version => !version.includes("-"));
assert(version !== undefined);
(parsedPackageJson.dependencies ??= {})[moduleName] = `~${version}`;
if (parsedPackageJson.devDependencies !== undefined) {
delete parsedPackageJson.devDependencies[moduleName];
}
2023-03-20 01:30:42 +01:00
2023-03-21 01:50:21 +01:00
{
let sourceCode = JSON.stringify(parsedPackageJson, undefined, 2);
if (await getIsPrettierAvailable()) {
sourceCode = await runPrettier({
sourceCode,
filePath: buildContext.packageJsonFilePath
});
}
2023-03-21 01:50:21 +01:00
2024-05-20 15:48:51 +02:00
fs.writeFileSync(
buildContext.packageJsonFilePath,
Buffer.from(sourceCode, "utf8")
2024-05-20 15:48:51 +02:00
);
2023-03-21 01:50:21 +01:00
}
await npmInstall({
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
});
console.log(chalk.green("Email theme initialized."));
2023-03-24 05:43:34 +01:00
}