249 lines
6.5 KiB
TypeScript
Raw Normal View History

#!/usr/bin/env node
import { termost } from "termost";
2024-05-19 04:02:36 +02:00
import { readThisNpmPackageVersion } from "./tools/readThisNpmPackageVersion";
import * as child_process from "child_process";
2024-06-28 19:03:19 +02:00
import { assertNoPnpmDlx } from "./tools/assertNoPnpmDlx";
2024-10-05 20:30:09 +02:00
import { getBuildContext } from "./shared/buildContext";
2024-10-05 20:30:09 +02:00
type CliCommandOptions = {
projectDirPath: string | undefined;
};
2024-06-28 19:03:19 +02:00
assertNoPnpmDlx();
const program = termost<CliCommandOptions>(
{
2024-05-20 15:48:51 +02:00
name: "keycloakify",
description: "Keycloakify CLI",
version: readThisNpmPackageVersion()
},
{
2024-05-20 15:48:51 +02:00
onException: error => {
console.error(error);
process.exit(1);
}
}
);
const optionsKeys: string[] = [];
2024-05-18 10:26:56 +02:00
program.option({
key: "projectDirPath",
2024-05-20 15:48:51 +02:00
name: (() => {
2024-05-18 10:26:56 +02:00
const long = "project";
const short = "p";
optionsKeys.push(long, short);
return { long, short };
})(),
2024-05-20 15:48:51 +02:00
description: [
2024-05-18 10:53:14 +02:00
`For monorepos, path to the keycloakify project.`,
"Example: `npx keycloakify build --project packages/keycloak-theme`",
"https://docs.keycloakify.dev/build-options#project-or-p-cli-option"
].join(" "),
2024-05-20 15:48:51 +02:00
defaultValue: undefined
2024-05-18 10:26:56 +02:00
});
function skip(_context: any, argv: { options: Record<string, unknown> }) {
2024-05-20 15:48:51 +02:00
const unrecognizedOptionKey = Object.keys(argv.options).find(
key => !optionsKeys.includes(key)
);
if (unrecognizedOptionKey !== undefined) {
2024-05-20 15:48:51 +02:00
console.error(
`keycloakify: Unrecognized option: ${
unrecognizedOptionKey.length === 1 ? "-" : "--"
}${unrecognizedOptionKey}`
);
process.exit(1);
}
return false;
}
program
.command({
2024-05-20 15:48:51 +02:00
name: "build",
description: "Build the theme (default subcommand)."
})
.task({
skip,
2024-10-05 20:30:09 +02:00
handler: async ({ projectDirPath }) => {
const { command } = await import("./keycloakify");
2024-05-18 08:56:11 +02:00
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
program
.command<{
port: number | undefined;
keycloakVersion: string | undefined;
realmJsonFilePath: string | undefined;
}>({
name: "start-keycloak",
description:
"Spin up a pre configured Docker image of Keycloak to test your theme."
})
.option({
key: "port",
name: (() => {
const name = "port";
optionsKeys.push(name);
2024-06-06 07:41:01 +02:00
return name;
})(),
description: ["Keycloak server port.", "Example `--port 8085`"].join(" "),
defaultValue: undefined
})
.option({
key: "keycloakVersion",
name: (() => {
const name = "keycloak-version";
optionsKeys.push(name);
return name;
})(),
description: [
"Use a specific version of Keycloak.",
"Example `--keycloak-version 21.1.1`"
].join(" "),
defaultValue: undefined
})
.option({
key: "realmJsonFilePath",
name: (() => {
const name = "import";
optionsKeys.push(name);
return name;
})(),
defaultValue: undefined,
description: [
"Import your own realm configuration file",
"Example `--import path/to/myrealm-realm.json`"
].join(" ")
})
.task({
skip,
handler: async ({ projectDirPath, keycloakVersion, port, realmJsonFilePath }) => {
const { command } = await import("./start-keycloak");
2024-06-06 07:41:01 +02:00
await command({
buildContext: getBuildContext({ projectDirPath }),
cliCommandOptions: { keycloakVersion, port, realmJsonFilePath }
});
}
});
2024-05-18 08:56:11 +02:00
program
.command({
name: "eject-page",
description: "Eject a Keycloak page."
})
.task({
skip,
handler: async ({ projectDirPath }) => {
const { command } = await import("./eject-page");
2024-10-05 20:30:09 +02:00
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
2024-10-05 20:30:09 +02:00
program
.command({
name: "add-story",
description: "Add *.stories.tsx file for a specific page to in your Storybook."
})
.task({
skip,
handler: async ({ projectDirPath }) => {
const { command } = await import("./add-story");
2024-10-05 20:30:09 +02:00
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
2024-10-05 20:30:09 +02:00
program
.command({
2024-10-07 21:02:51 +02:00
name: "initialize-email-theme",
description: "Initialize an email theme."
})
.task({
skip,
handler: async ({ projectDirPath }) => {
const { command } = await import("./initialize-email-theme");
2024-10-05 20:30:09 +02:00
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
program
.command({
name: "initialize-account-theme",
description: "Initialize the account theme."
})
.task({
skip,
2024-10-05 20:30:09 +02:00
handler: async ({ projectDirPath }) => {
2024-07-25 18:41:07 +02:00
const { command } = await import("./initialize-account-theme");
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
program
.command({
name: "copy-keycloak-resources-to-public",
description:
"(Webpack/Create-React-App only) Copy Keycloak default theme resources to the public directory."
})
.task({
skip,
handler: async ({ projectDirPath }) => {
const { command } = await import("./copy-keycloak-resources-to-public");
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
2024-10-05 20:30:09 +02:00
program
.command({
name: "update-kc-gen",
description:
"(Webpack/Create-React-App only) Create/update the kc.gen.ts file in your project."
})
.task({
skip,
handler: async ({ projectDirPath }) => {
const { command } = await import("./update-kc-gen");
2024-10-05 20:30:09 +02:00
await command({ buildContext: getBuildContext({ projectDirPath }) });
}
});
// Fallback to build command if no command is provided
{
const [, , ...rest] = process.argv;
2024-05-20 15:48:51 +02:00
if (
rest.length === 0 ||
(rest[0].startsWith("-") && rest[0] !== "--help" && rest[0] !== "-h")
) {
const { status } = child_process.spawnSync(
"npx",
["keycloakify", "build", ...rest],
{
stdio: "inherit"
}
);
process.exit(status ?? 1);
}
}