checkpoint
This commit is contained in:
parent
93fcf96cde
commit
a60a0d0696
@ -1,19 +0,0 @@
|
||||
import * as fs from "fs";
|
||||
import { join as pathJoin } from "path";
|
||||
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
|
||||
|
||||
export function copyBoilerplate(params: { adminThemeSrcDirPath: string }) {
|
||||
const { adminThemeSrcDirPath } = params;
|
||||
|
||||
fs.cpSync(
|
||||
pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
"src",
|
||||
"bin",
|
||||
"initialize-admin-theme",
|
||||
"src"
|
||||
),
|
||||
adminThemeSrcDirPath,
|
||||
{ recursive: true }
|
||||
);
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from "./initialize-admin-theme";
|
@ -1,60 +0,0 @@
|
||||
import type { BuildContext } from "../shared/buildContext";
|
||||
import chalk from "chalk";
|
||||
import { join as pathJoin, relative as pathRelative } from "path";
|
||||
import * as fs from "fs";
|
||||
import { command as updateKcGenCommand } from "../update-kc-gen";
|
||||
import { maybeDelegateCommandToCustomHandler } from "../shared/customHandler_delegate";
|
||||
import { exitIfUncommittedChanges } from "../shared/exitIfUncommittedChanges";
|
||||
import { initializeAdminTheme } from "./initializeAdminTheme";
|
||||
|
||||
export async function command(params: { buildContext: BuildContext }) {
|
||||
const { buildContext } = params;
|
||||
|
||||
const { hasBeenHandled } = maybeDelegateCommandToCustomHandler({
|
||||
commandName: "initialize-admin-theme",
|
||||
buildContext
|
||||
});
|
||||
|
||||
if (hasBeenHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const adminThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "admin");
|
||||
|
||||
if (
|
||||
fs.existsSync(adminThemeSrcDirPath) &&
|
||||
fs.readdirSync(adminThemeSrcDirPath).length > 0
|
||||
) {
|
||||
console.warn(
|
||||
chalk.red(
|
||||
`There is already a ${pathRelative(
|
||||
process.cwd(),
|
||||
adminThemeSrcDirPath
|
||||
)} directory in your project. Aborting.`
|
||||
)
|
||||
);
|
||||
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
exitIfUncommittedChanges({
|
||||
projectDirPath: buildContext.projectDirPath
|
||||
});
|
||||
|
||||
await initializeAdminTheme({
|
||||
adminThemeSrcDirPath,
|
||||
buildContext
|
||||
});
|
||||
|
||||
await updateKcGenCommand({
|
||||
buildContext: {
|
||||
...buildContext,
|
||||
implementedThemeTypes: {
|
||||
...buildContext.implementedThemeTypes,
|
||||
admin: {
|
||||
isImplemented: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
|
||||
import type { BuildContext } from "../shared/buildContext";
|
||||
import * as fs from "fs";
|
||||
import chalk from "chalk";
|
||||
import {
|
||||
getLatestsSemVersionedTag,
|
||||
type BuildContextLike as BuildContextLike_getLatestsSemVersionedTag
|
||||
} from "../shared/getLatestsSemVersionedTag";
|
||||
import { SemVer } from "../tools/SemVer";
|
||||
import fetch from "make-fetch-happen";
|
||||
import { z } from "zod";
|
||||
import { assert, type Equals } from "tsafe/assert";
|
||||
import { is } from "tsafe/is";
|
||||
import { id } from "tsafe/id";
|
||||
import { npmInstall } from "../tools/npmInstall";
|
||||
import { copyBoilerplate } from "./copyBoilerplate";
|
||||
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
|
||||
|
||||
type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
|
||||
fetchOptions: BuildContext["fetchOptions"];
|
||||
packageJsonFilePath: string;
|
||||
};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export async function initializeAdminTheme(params: {
|
||||
adminThemeSrcDirPath: string;
|
||||
buildContext: BuildContextLike;
|
||||
}) {
|
||||
const { adminThemeSrcDirPath, buildContext } = params;
|
||||
|
||||
const OWNER = "keycloakify";
|
||||
const REPO = "keycloak-admin-ui";
|
||||
|
||||
const [semVersionedTag] = await getLatestsSemVersionedTag({
|
||||
owner: OWNER,
|
||||
repo: REPO,
|
||||
count: 1,
|
||||
doIgnoreReleaseCandidates: false,
|
||||
buildContext
|
||||
});
|
||||
|
||||
const dependencies = await fetch(
|
||||
`https://raw.githubusercontent.com/${OWNER}/${REPO}/${semVersionedTag.tag}/dependencies.gen.json`,
|
||||
buildContext.fetchOptions
|
||||
)
|
||||
.then(r => r.json())
|
||||
.then(
|
||||
(() => {
|
||||
type Dependencies = {
|
||||
dependencies: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
};
|
||||
|
||||
const zDependencies = (() => {
|
||||
type TargetType = Dependencies;
|
||||
|
||||
const zTargetType = z.object({
|
||||
dependencies: z.record(z.string()),
|
||||
devDependencies: z.record(z.string()).optional()
|
||||
});
|
||||
|
||||
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
|
||||
|
||||
return id<z.ZodType<TargetType>>(zTargetType);
|
||||
})();
|
||||
|
||||
return o => zDependencies.parse(o);
|
||||
})()
|
||||
);
|
||||
|
||||
dependencies.dependencies["@keycloakify/keycloak-admin-ui"] = SemVer.stringify(
|
||||
semVersionedTag.version
|
||||
);
|
||||
|
||||
const parsedPackageJson = (() => {
|
||||
type ParsedPackageJson = {
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
};
|
||||
|
||||
const zParsedPackageJson = (() => {
|
||||
type TargetType = ParsedPackageJson;
|
||||
|
||||
const zTargetType = z.object({
|
||||
dependencies: z.record(z.string()).optional(),
|
||||
devDependencies: z.record(z.string()).optional()
|
||||
});
|
||||
|
||||
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
|
||||
|
||||
return id<z.ZodType<TargetType>>(zTargetType);
|
||||
})();
|
||||
const parsedPackageJson = JSON.parse(
|
||||
fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8")
|
||||
);
|
||||
|
||||
zParsedPackageJson.parse(parsedPackageJson);
|
||||
|
||||
assert(is<ParsedPackageJson>(parsedPackageJson));
|
||||
|
||||
return parsedPackageJson;
|
||||
})();
|
||||
|
||||
parsedPackageJson.dependencies = {
|
||||
...parsedPackageJson.dependencies,
|
||||
...dependencies.dependencies
|
||||
};
|
||||
|
||||
parsedPackageJson.devDependencies = {
|
||||
...parsedPackageJson.devDependencies,
|
||||
...dependencies.devDependencies
|
||||
};
|
||||
|
||||
if (Object.keys(parsedPackageJson.devDependencies).length === 0) {
|
||||
delete parsedPackageJson.devDependencies;
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
buildContext.packageJsonFilePath,
|
||||
JSON.stringify(parsedPackageJson, undefined, 4)
|
||||
);
|
||||
|
||||
run_npm_install: {
|
||||
if (
|
||||
JSON.parse(
|
||||
fs
|
||||
.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json"))
|
||||
.toString("utf8")
|
||||
)["version"] === "0.0.0"
|
||||
) {
|
||||
//NOTE: Linked version
|
||||
break run_npm_install;
|
||||
}
|
||||
|
||||
npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) });
|
||||
}
|
||||
|
||||
copyBoilerplate({ adminThemeSrcDirPath });
|
||||
|
||||
console.log(
|
||||
[
|
||||
chalk.green("The Admin theme has been successfully initialized."),
|
||||
`Using Admin UI of Keycloak version: ${chalk.bold(semVersionedTag.tag.split("-")[0])}`,
|
||||
`Directory created: ${chalk.bold(pathRelative(process.cwd(), adminThemeSrcDirPath))}`,
|
||||
`Dependencies added to your project's package.json: `,
|
||||
chalk.bold(JSON.stringify(dependencies, null, 2))
|
||||
].join("\n")
|
||||
);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import type { KcContextLike } from "@keycloakify/keycloak-admin-ui";
|
||||
import type { KcEnvName } from "../kc.gen";
|
||||
|
||||
export type KcContext = KcContextLike & {
|
||||
themeType: "admin";
|
||||
properties: Record<KcEnvName, string>;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
import { lazy } from "react";
|
||||
import { KcAdminUiLoader } from "@keycloakify/keycloak-admin-ui";
|
||||
import type { KcContext } from "./KcContext";
|
||||
|
||||
const KcAdminUi = lazy(() => import("@keycloakify/keycloak-admin-ui/KcAdminUi"));
|
||||
|
||||
export default function KcPage(props: { kcContext: KcContext }) {
|
||||
const { kcContext } = props;
|
||||
|
||||
return <KcAdminUiLoader kcContext={kcContext} KcAdminUi={KcAdminUi} />;
|
||||
}
|
157
src/bin/sync-ui-modules/installUiModulesPeerDependencies.ts
Normal file
157
src/bin/sync-ui-modules/installUiModulesPeerDependencies.ts
Normal file
@ -0,0 +1,157 @@
|
||||
import { assert, type Equals } from "tsafe/assert";
|
||||
import { is } from "tsafe/is";
|
||||
import type { BuildContext } from "../shared/buildContext";
|
||||
import type { UiModuleMeta } from "./uiModuleMeta";
|
||||
import { z } from "zod";
|
||||
import { id } from "tsafe/id";
|
||||
import * as fsPr from "fs/promises";
|
||||
import { SemVer } from "../tools/SemVer";
|
||||
import { same } from "evt/tools/inDepth/same";
|
||||
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
||||
import { npmInstall } from "../tools/npmInstall";
|
||||
|
||||
export type BuildContextLike = {
|
||||
packageJsonFilePath: string;
|
||||
};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export type UiModuleMetaLike = {
|
||||
moduleName: string;
|
||||
peerDependencies: Record<string, string>;
|
||||
};
|
||||
|
||||
assert<UiModuleMeta extends UiModuleMetaLike ? true : false>();
|
||||
|
||||
export async function installUiModulesPeerDependencies(params: {
|
||||
buildContext: BuildContextLike;
|
||||
uiModuleMetas: UiModuleMetaLike[];
|
||||
}): Promise<void | never> {
|
||||
const { buildContext, uiModuleMetas } = params;
|
||||
|
||||
const { uiModulesPerDependencies } = (() => {
|
||||
const uiModulesPerDependencies: Record<string, string> = {};
|
||||
|
||||
for (const { peerDependencies } of uiModuleMetas) {
|
||||
for (const [peerDependencyName, versionRange_candidate] of Object.entries(
|
||||
peerDependencies
|
||||
)) {
|
||||
const versionRange = (() => {
|
||||
const versionRange_current =
|
||||
uiModulesPerDependencies[peerDependencyName];
|
||||
|
||||
if (versionRange_current === undefined) {
|
||||
return versionRange_candidate;
|
||||
}
|
||||
|
||||
if (versionRange_current === "*") {
|
||||
return versionRange_candidate;
|
||||
}
|
||||
|
||||
if (versionRange_candidate === "*") {
|
||||
return versionRange_current;
|
||||
}
|
||||
|
||||
const { versionRange } = [
|
||||
versionRange_current,
|
||||
versionRange_candidate
|
||||
]
|
||||
.map(versionRange => ({
|
||||
versionRange,
|
||||
semVer: SemVer.parse(
|
||||
(() => {
|
||||
if (
|
||||
versionRange.startsWith("^") ||
|
||||
versionRange.startsWith("~")
|
||||
) {
|
||||
return versionRange.slice(1);
|
||||
}
|
||||
|
||||
return versionRange;
|
||||
})()
|
||||
)
|
||||
}))
|
||||
.sort((a, b) => SemVer.compare(b.semVer, a.semVer))[0];
|
||||
|
||||
return versionRange;
|
||||
})();
|
||||
|
||||
uiModulesPerDependencies[peerDependencyName] = versionRange;
|
||||
}
|
||||
}
|
||||
|
||||
return { uiModulesPerDependencies };
|
||||
})();
|
||||
|
||||
const parsedPackageJson = await (async () => {
|
||||
type ParsedPackageJson = {
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
};
|
||||
|
||||
const zParsedPackageJson = (() => {
|
||||
type TargetType = ParsedPackageJson;
|
||||
|
||||
const zParsedPackageJson = z.object({
|
||||
dependencies: z.record(z.string()).optional(),
|
||||
devDependencies: z.record(z.string()).optional()
|
||||
});
|
||||
|
||||
type InferredType = z.infer<typeof zParsedPackageJson>;
|
||||
|
||||
assert<Equals<InferredType, TargetType>>();
|
||||
|
||||
return id<z.ZodType<TargetType>>(zParsedPackageJson);
|
||||
})();
|
||||
|
||||
const parsedPackageJson = JSON.parse(
|
||||
(await fsPr.readFile(buildContext.packageJsonFilePath)).toString("utf8")
|
||||
);
|
||||
|
||||
zParsedPackageJson.parse(parsedPackageJson);
|
||||
|
||||
assert(is<ParsedPackageJson>(parsedPackageJson));
|
||||
|
||||
return parsedPackageJson;
|
||||
})();
|
||||
|
||||
const parsedPackageJson_before = JSON.parse(JSON.stringify(parsedPackageJson));
|
||||
|
||||
for (const [moduleName, versionRange] of Object.entries(uiModulesPerDependencies)) {
|
||||
if (moduleName.startsWith("@types/")) {
|
||||
(parsedPackageJson.devDependencies ??= {})[moduleName] = versionRange;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsedPackageJson.devDependencies !== undefined) {
|
||||
delete parsedPackageJson.devDependencies[moduleName];
|
||||
}
|
||||
|
||||
(parsedPackageJson.dependencies ??= {})[moduleName] = versionRange;
|
||||
}
|
||||
|
||||
if (same(parsedPackageJson, parsedPackageJson_before)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let packageJsonContentStr = JSON.stringify(parsedPackageJson, null, 2);
|
||||
|
||||
format: {
|
||||
if (!(await getIsPrettierAvailable())) {
|
||||
break format;
|
||||
}
|
||||
|
||||
packageJsonContentStr = await runPrettier({
|
||||
sourceCode: packageJsonContentStr,
|
||||
filePath: buildContext.packageJsonFilePath
|
||||
});
|
||||
}
|
||||
|
||||
await fsPr.writeFile(buildContext.packageJsonFilePath, packageJsonContentStr);
|
||||
|
||||
npmInstall({
|
||||
packageJsonDirPath: buildContext.packageJsonFilePath
|
||||
});
|
||||
|
||||
process.exit(0);
|
||||
}
|
@ -1,9 +1,15 @@
|
||||
import * as fsPr from "fs/promises";
|
||||
import { join as pathJoin, sep as pathSep, dirname as pathDirname } from "path";
|
||||
import {
|
||||
join as pathJoin,
|
||||
sep as pathSep,
|
||||
dirname as pathDirname,
|
||||
relative as pathRelative
|
||||
} from "path";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { BuildContext } from "../shared/buildContext";
|
||||
import type { UiModuleMeta } from "./uiModuleMeta";
|
||||
import { existsAsync } from "../tools/fs.existsAsync";
|
||||
import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath";
|
||||
|
||||
export type BuildContextLike = {
|
||||
themeSrcDirPath: string;
|
||||
@ -82,3 +88,48 @@ export async function writeManagedGitignoreFile(params: {
|
||||
|
||||
await fsPr.writeFile(filePath, content_new);
|
||||
}
|
||||
|
||||
export async function readManagedGitignoreFile(params: {
|
||||
buildContext: BuildContextLike;
|
||||
}): Promise<{
|
||||
ejectedFilesRelativePaths: string[];
|
||||
}> {
|
||||
const { buildContext } = params;
|
||||
|
||||
const filePath = pathJoin(buildContext.themeSrcDirPath, ".gitignore");
|
||||
|
||||
if (!(await existsAsync(filePath))) {
|
||||
return { ejectedFilesRelativePaths: [] };
|
||||
}
|
||||
|
||||
const contentStr = (await fsPr.readFile(filePath)).toString("utf8");
|
||||
|
||||
const payload = (() => {
|
||||
const index_start = contentStr.indexOf(DELIMITER_START);
|
||||
const index_end = contentStr.indexOf(DELIMITER_END);
|
||||
|
||||
if (index_start === -1 || index_end === -1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return contentStr.slice(index_start + DELIMITER_START.length, index_end).trim();
|
||||
})();
|
||||
|
||||
if (payload === undefined) {
|
||||
return { ejectedFilesRelativePaths: [] };
|
||||
}
|
||||
|
||||
const ejectedFilesRelativePaths = payload
|
||||
.split("\n")
|
||||
.map(line => line.trim())
|
||||
.filter(line => line !== "")
|
||||
.map(line =>
|
||||
getAbsoluteAndInOsFormatPath({
|
||||
cwd: buildContext.themeSrcDirPath,
|
||||
pathIsh: line
|
||||
})
|
||||
)
|
||||
.map(filePath => pathRelative(buildContext.themeSrcDirPath, filePath));
|
||||
|
||||
return { ejectedFilesRelativePaths };
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
||||
{
|
||||
binName: "bun",
|
||||
lockFileBasename: "bun.lockdb"
|
||||
},
|
||||
{
|
||||
binName: "deno",
|
||||
lockFileBasename: "deno.lock"
|
||||
}
|
||||
] as const;
|
||||
|
||||
@ -37,14 +41,11 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
throw new Error(
|
||||
"No lock file found, cannot tell which package manager to use for installing dependencies."
|
||||
);
|
||||
})();
|
||||
|
||||
install_dependencies: {
|
||||
if (packageManagerBinName === undefined) {
|
||||
break install_dependencies;
|
||||
}
|
||||
|
||||
console.log(`Installing the new dependencies...`);
|
||||
|
||||
try {
|
||||
@ -59,5 +60,4 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user