keycloakify 11.8.46 → 11.8.47-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/254.index.js +283 -0
- package/bin/30.index.js +25 -0
- package/bin/{864.index.js → 309.index.js} +6944 -28439
- package/bin/311.index.js +198 -0
- package/bin/{313.index.js → 355.index.js} +101 -147
- package/bin/{84.index.js → 502.index.js} +147 -101
- package/bin/626.index.js +194 -0
- package/bin/{698.index.js → 656.index.js} +101 -147
- package/bin/675.index.js +177 -0
- package/bin/69.index.js +1 -1
- package/bin/762.index.js +1475 -0
- package/bin/780.index.js +4 -2
- package/bin/786.index.js +115 -0
- package/bin/895.index.js +21501 -0
- package/bin/{618.index.js → 932.index.js} +117 -163
- package/bin/949.index.js +1 -1
- package/bin/97.index.js +537 -4
- package/bin/init/index.d.ts +1 -0
- package/bin/init/init.d.ts +3 -0
- package/bin/init/setupEslint.d.ts +4 -0
- package/bin/init/setupVitePluginIfNeeded.d.ts +4 -0
- package/bin/initialize-login-theme.d.ts +4 -0
- package/bin/main.js +19 -30
- package/bin/shared/customHandler.d.ts +1 -1
- package/bin/shared/customHandler.js.map +1 -1
- package/package.json +23 -7
- package/src/bin/init/index.ts +1 -0
- package/src/bin/init/init.ts +354 -0
- package/src/bin/init/setupEslint.ts +80 -0
- package/src/bin/init/setupVitePluginIfNeeded.ts +143 -0
- package/src/bin/initialize-account-theme/initialize-account-theme.ts +4 -0
- package/src/bin/initialize-login-theme.ts +323 -0
- package/src/bin/main.ts +14 -0
- package/src/bin/shared/buildContext.ts +2 -37
- package/src/bin/shared/customHandler.ts +3 -1
- package/src/bin/sync-extensions/extensionModuleMeta.ts +89 -73
- package/src/bin/sync-extensions/managedGitignoreFiles.ts +32 -2
- package/vite-plugin/index.js +1 -24
- package/bin/433.index.js +0 -140
@@ -0,0 +1,143 @@
|
|
1
|
+
import { join as pathJoin } from "path";
|
2
|
+
import { existsAsync } from "../tools/fs.existsAsync";
|
3
|
+
import * as fs from "fs/promises";
|
4
|
+
import * as recast from "recast";
|
5
|
+
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
6
|
+
import * as babelParser from "@babel/parser";
|
7
|
+
import babelGenerate from "@babel/generator";
|
8
|
+
import * as babelTypes from "@babel/types";
|
9
|
+
|
10
|
+
/** Best effort to setup the Keycloakify vite plugin automatically */
|
11
|
+
export async function setupVitePluginIfNeeded(params: { projectDirPath: string }) {
|
12
|
+
const { projectDirPath } = params;
|
13
|
+
|
14
|
+
const viteConfigTsFilePath = pathJoin(projectDirPath, "vite.config.ts");
|
15
|
+
|
16
|
+
if (!(await existsAsync(viteConfigTsFilePath))) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const viteConfigTsContent = (await fs.readFile(viteConfigTsFilePath)).toString(
|
21
|
+
"utf8"
|
22
|
+
);
|
23
|
+
|
24
|
+
if (viteConfigTsContent.includes("keycloakify")) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
const root = recast.parse(viteConfigTsContent, {
|
29
|
+
parser: {
|
30
|
+
parse: (code: string) =>
|
31
|
+
babelParser.parse(code, {
|
32
|
+
sourceType: "module",
|
33
|
+
plugins: ["typescript"]
|
34
|
+
}),
|
35
|
+
generator: babelGenerate,
|
36
|
+
types: babelTypes
|
37
|
+
}
|
38
|
+
});
|
39
|
+
|
40
|
+
/* Before:
|
41
|
+
import { defineConfig } from "vite";
|
42
|
+
import react from "@vitejs/plugin-react";
|
43
|
+
|
44
|
+
// https://vitejs.dev/config/
|
45
|
+
export default defineConfig({
|
46
|
+
plugins: [ react() ]
|
47
|
+
});
|
48
|
+
*/
|
49
|
+
|
50
|
+
/* After:
|
51
|
+
import { defineConfig } from "vite";
|
52
|
+
import react from "@vitejs/plugin-react";
|
53
|
+
import { keycloakify } from "keycloakify/vite-plugin";
|
54
|
+
|
55
|
+
// https://vitejs.dev/config/
|
56
|
+
export default defineConfig({
|
57
|
+
plugins: [
|
58
|
+
react(),
|
59
|
+
keycloakify({
|
60
|
+
accountThemeImplementation: "none"
|
61
|
+
})
|
62
|
+
]
|
63
|
+
});
|
64
|
+
*/
|
65
|
+
|
66
|
+
recast.visit(root, {
|
67
|
+
visitProgram(path) {
|
68
|
+
const body = path.node.body;
|
69
|
+
|
70
|
+
// Add import: import { keycloakify } from "keycloakify/vite-plugin";
|
71
|
+
const importDeclaration = babelTypes.importDeclaration(
|
72
|
+
[
|
73
|
+
babelTypes.importSpecifier(
|
74
|
+
babelTypes.identifier("keycloakify"),
|
75
|
+
babelTypes.identifier("keycloakify")
|
76
|
+
)
|
77
|
+
],
|
78
|
+
babelTypes.stringLiteral("keycloakify/vite-plugin")
|
79
|
+
);
|
80
|
+
// @ts-expect-error
|
81
|
+
body.unshift(importDeclaration);
|
82
|
+
|
83
|
+
this.traverse(path);
|
84
|
+
},
|
85
|
+
visitCallExpression(path) {
|
86
|
+
const { node } = path;
|
87
|
+
|
88
|
+
if (
|
89
|
+
// @ts-expect-error
|
90
|
+
babelTypes.isIdentifier(node.callee, { name: "defineConfig" }) &&
|
91
|
+
node.arguments.length === 1 &&
|
92
|
+
// @ts-expect-error
|
93
|
+
babelTypes.isObjectExpression(node.arguments[0])
|
94
|
+
) {
|
95
|
+
const configObject = node.arguments[0];
|
96
|
+
const pluginsProp = configObject.properties.find(
|
97
|
+
prop =>
|
98
|
+
// @ts-expect-error
|
99
|
+
babelTypes.isObjectProperty(prop) &&
|
100
|
+
babelTypes.isIdentifier(prop.key, { name: "plugins" }) &&
|
101
|
+
babelTypes.isArrayExpression(prop.value)
|
102
|
+
) as babelTypes.ObjectProperty | undefined;
|
103
|
+
|
104
|
+
if (pluginsProp && babelTypes.isArrayExpression(pluginsProp.value)) {
|
105
|
+
// Append keycloakify plugin config
|
106
|
+
const keycloakifyCall = babelTypes.callExpression(
|
107
|
+
babelTypes.identifier("keycloakify"),
|
108
|
+
[
|
109
|
+
babelTypes.objectExpression([
|
110
|
+
babelTypes.objectProperty(
|
111
|
+
babelTypes.identifier("accountThemeImplementation"),
|
112
|
+
babelTypes.stringLiteral("none")
|
113
|
+
)
|
114
|
+
])
|
115
|
+
]
|
116
|
+
);
|
117
|
+
|
118
|
+
pluginsProp.value.elements.push(keycloakifyCall);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
this.traverse(path);
|
123
|
+
}
|
124
|
+
});
|
125
|
+
|
126
|
+
let viteConfigTsContent_modified = babelGenerate(root).code;
|
127
|
+
|
128
|
+
format: {
|
129
|
+
if (!(await getIsPrettierAvailable())) {
|
130
|
+
break format;
|
131
|
+
}
|
132
|
+
|
133
|
+
viteConfigTsContent_modified = await runPrettier({
|
134
|
+
sourceCode: viteConfigTsContent_modified,
|
135
|
+
filePath: viteConfigTsFilePath
|
136
|
+
});
|
137
|
+
}
|
138
|
+
|
139
|
+
await fs.writeFile(
|
140
|
+
viteConfigTsFilePath,
|
141
|
+
Buffer.from(viteConfigTsContent_modified, "utf8")
|
142
|
+
);
|
143
|
+
}
|
@@ -26,12 +26,16 @@ export async function command(params: { buildContext: BuildContext }) {
|
|
26
26
|
projectDirPath: buildContext.projectDirPath
|
27
27
|
});
|
28
28
|
|
29
|
+
console.log(chalk.cyan("Which account theme type?"));
|
30
|
+
|
29
31
|
const { value: accountThemeType } = await cliSelect({
|
30
32
|
values: ["Single-Page" as const, "Multi-Page" as const]
|
31
33
|
}).catch(() => {
|
32
34
|
process.exit(-1);
|
33
35
|
});
|
34
36
|
|
37
|
+
console.log(`${accountThemeType}\n`);
|
38
|
+
|
35
39
|
switch (accountThemeType) {
|
36
40
|
case "Multi-Page":
|
37
41
|
{
|
@@ -0,0 +1,323 @@
|
|
1
|
+
import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
|
2
|
+
import { dirname as pathDirname, join as pathJoin } from "path";
|
3
|
+
import type { BuildContext } from "./shared/buildContext";
|
4
|
+
import * as fs from "fs/promises";
|
5
|
+
import { assert, is, type Equals } from "tsafe/assert";
|
6
|
+
import { id } from "tsafe/id";
|
7
|
+
import { addSyncExtensionsToPostinstallScript } from "./shared/addSyncExtensionsToPostinstallScript";
|
8
|
+
import { getIsPrettierAvailable, runPrettier } from "./tools/runPrettier";
|
9
|
+
import { npmInstall } from "./tools/npmInstall";
|
10
|
+
import * as child_process from "child_process";
|
11
|
+
import { z } from "zod";
|
12
|
+
import chalk from "chalk";
|
13
|
+
import cliSelect from "cli-select";
|
14
|
+
import { existsAsync } from "./tools/fs.existsAsync";
|
15
|
+
|
16
|
+
export async function command(params: { buildContext: BuildContext }) {
|
17
|
+
const { buildContext } = params;
|
18
|
+
|
19
|
+
const { hasBeenHandled } = await maybeDelegateCommandToCustomHandler({
|
20
|
+
commandName: "initialize-login-theme",
|
21
|
+
buildContext
|
22
|
+
});
|
23
|
+
|
24
|
+
if (hasBeenHandled) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
if (
|
29
|
+
buildContext.implementedThemeTypes.login.isImplemented ||
|
30
|
+
buildContext.implementedThemeTypes.login.isImplemented_native
|
31
|
+
) {
|
32
|
+
console.warn(chalk.red("There is already a login theme in your project"));
|
33
|
+
|
34
|
+
process.exit(-1);
|
35
|
+
}
|
36
|
+
|
37
|
+
const parsedPackageJson = await (async () => {
|
38
|
+
type ParsedPackageJson = {
|
39
|
+
scripts?: Record<string, string | undefined>;
|
40
|
+
dependencies?: Record<string, string | undefined>;
|
41
|
+
devDependencies?: Record<string, string | undefined>;
|
42
|
+
};
|
43
|
+
|
44
|
+
const zParsedPackageJson = (() => {
|
45
|
+
type TargetType = ParsedPackageJson;
|
46
|
+
|
47
|
+
const zTargetType = z.object({
|
48
|
+
scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
|
49
|
+
dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
|
50
|
+
devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
|
51
|
+
});
|
52
|
+
|
53
|
+
assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
|
54
|
+
|
55
|
+
return id<z.ZodType<TargetType>>(zTargetType);
|
56
|
+
})();
|
57
|
+
const parsedPackageJson = JSON.parse(
|
58
|
+
(await fs.readFile(buildContext.packageJsonFilePath)).toString("utf8")
|
59
|
+
);
|
60
|
+
|
61
|
+
zParsedPackageJson.parse(parsedPackageJson);
|
62
|
+
|
63
|
+
assert(is<ParsedPackageJson>(parsedPackageJson));
|
64
|
+
|
65
|
+
return parsedPackageJson;
|
66
|
+
})();
|
67
|
+
|
68
|
+
addSyncExtensionsToPostinstallScript({
|
69
|
+
parsedPackageJson,
|
70
|
+
buildContext
|
71
|
+
});
|
72
|
+
|
73
|
+
const doInstallStories = await (async () => {
|
74
|
+
console.log(chalk.cyan(`\nDo you want to install the Stories?`));
|
75
|
+
|
76
|
+
const YES = "Yes (Recommended)";
|
77
|
+
const NO = "No";
|
78
|
+
|
79
|
+
const { value } = await cliSelect({
|
80
|
+
values: [YES, NO]
|
81
|
+
}).catch(() => {
|
82
|
+
process.exit(-1);
|
83
|
+
});
|
84
|
+
|
85
|
+
console.log(`${value}\n`);
|
86
|
+
|
87
|
+
return value === YES;
|
88
|
+
})();
|
89
|
+
|
90
|
+
install_storybook: {
|
91
|
+
if (!doInstallStories) {
|
92
|
+
break install_storybook;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (buildContext.bundler !== "vite") {
|
96
|
+
break install_storybook;
|
97
|
+
}
|
98
|
+
|
99
|
+
if (
|
100
|
+
Object.keys({
|
101
|
+
...parsedPackageJson.dependencies,
|
102
|
+
...parsedPackageJson.devDependencies
|
103
|
+
}).includes("storybook")
|
104
|
+
) {
|
105
|
+
break install_storybook;
|
106
|
+
}
|
107
|
+
|
108
|
+
(parsedPackageJson.scripts ??= {})["storybook"] = "storybook dev -p 6006";
|
109
|
+
parsedPackageJson.scripts["build-storybook"] = "storybook build";
|
110
|
+
|
111
|
+
(parsedPackageJson.devDependencies ??= {})["storybook"] = "^9.0.4";
|
112
|
+
parsedPackageJson.devDependencies["@storybook/react-vite"] = "^9.0.4";
|
113
|
+
|
114
|
+
const files: { relativeFilePath: string; fileContent: string }[] = [
|
115
|
+
{
|
116
|
+
relativeFilePath: "main.ts",
|
117
|
+
fileContent: [
|
118
|
+
`import type { StorybookConfig } from "@storybook/react-vite";`,
|
119
|
+
``,
|
120
|
+
`const config: StorybookConfig = {`,
|
121
|
+
` stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],`,
|
122
|
+
` addons: [],`,
|
123
|
+
` framework: {`,
|
124
|
+
` name: "@storybook/react-vite",`,
|
125
|
+
` options: {}`,
|
126
|
+
` },`,
|
127
|
+
`};`,
|
128
|
+
`export default config;`,
|
129
|
+
``
|
130
|
+
].join("\n")
|
131
|
+
},
|
132
|
+
{
|
133
|
+
relativeFilePath: "preview.ts",
|
134
|
+
fileContent: storybookPreviewTsFileContent
|
135
|
+
}
|
136
|
+
];
|
137
|
+
|
138
|
+
for (let { relativeFilePath, fileContent } of files) {
|
139
|
+
const filePath = pathJoin(
|
140
|
+
buildContext.projectDirPath,
|
141
|
+
".storybook",
|
142
|
+
relativeFilePath
|
143
|
+
);
|
144
|
+
|
145
|
+
{
|
146
|
+
const dirPath = pathDirname(filePath);
|
147
|
+
|
148
|
+
if (!(await existsAsync(dirPath))) {
|
149
|
+
await fs.mkdir(dirPath, { recursive: true });
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
run_prettier: {
|
154
|
+
if (!(await getIsPrettierAvailable())) {
|
155
|
+
break run_prettier;
|
156
|
+
}
|
157
|
+
|
158
|
+
fileContent = await runPrettier({
|
159
|
+
filePath: filePath,
|
160
|
+
sourceCode: fileContent
|
161
|
+
});
|
162
|
+
}
|
163
|
+
|
164
|
+
await fs.writeFile(filePath, Buffer.from(fileContent, "utf8"));
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
{
|
169
|
+
const moduleName = "@keycloakify/login-ui";
|
170
|
+
|
171
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
172
|
+
|
173
|
+
(parsedPackageJson.dependencies ??= {})[moduleName] = `~${latestVersion}`;
|
174
|
+
|
175
|
+
if (parsedPackageJson.devDependencies !== undefined) {
|
176
|
+
delete parsedPackageJson.devDependencies[moduleName];
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
install_stories: {
|
181
|
+
if (!doInstallStories) {
|
182
|
+
break install_stories;
|
183
|
+
}
|
184
|
+
|
185
|
+
const moduleName = "@keycloakify/login-ui-storybook";
|
186
|
+
|
187
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
188
|
+
|
189
|
+
(parsedPackageJson.devDependencies ??= {})[moduleName] = `~${latestVersion}`;
|
190
|
+
|
191
|
+
delete parsedPackageJson.dependencies[moduleName];
|
192
|
+
}
|
193
|
+
|
194
|
+
{
|
195
|
+
let sourceCode = JSON.stringify(parsedPackageJson, null, 2);
|
196
|
+
|
197
|
+
if (await getIsPrettierAvailable()) {
|
198
|
+
sourceCode = await runPrettier({
|
199
|
+
sourceCode,
|
200
|
+
filePath: buildContext.packageJsonFilePath
|
201
|
+
});
|
202
|
+
}
|
203
|
+
|
204
|
+
await fs.writeFile(
|
205
|
+
buildContext.packageJsonFilePath,
|
206
|
+
Buffer.from(sourceCode, "utf8")
|
207
|
+
);
|
208
|
+
}
|
209
|
+
|
210
|
+
await npmInstall({
|
211
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
215
|
+
async function getModuleLatestVersion(params: { moduleName: string }) {
|
216
|
+
const { moduleName } = params;
|
217
|
+
|
218
|
+
const versions = ((): string[] => {
|
219
|
+
const cmdOutput = child_process
|
220
|
+
.execSync(`npm show ${moduleName} versions --json`)
|
221
|
+
.toString("utf8")
|
222
|
+
.trim();
|
223
|
+
|
224
|
+
const versions = JSON.parse(cmdOutput) as string | string[];
|
225
|
+
|
226
|
+
// NOTE: Bug in some older npm versions
|
227
|
+
if (typeof versions === "string") {
|
228
|
+
return [versions];
|
229
|
+
}
|
230
|
+
|
231
|
+
return versions;
|
232
|
+
})();
|
233
|
+
|
234
|
+
const version = versions.reverse().filter(version => !version.includes("-"))[0];
|
235
|
+
|
236
|
+
assert(version !== undefined);
|
237
|
+
|
238
|
+
return version;
|
239
|
+
}
|
240
|
+
|
241
|
+
const storybookPreviewTsFileContent = [
|
242
|
+
`import type { Preview } from "@storybook/react-vite";`,
|
243
|
+
``,
|
244
|
+
`const preview: Preview = {`,
|
245
|
+
` parameters: {`,
|
246
|
+
` controls: {`,
|
247
|
+
` matchers: {`,
|
248
|
+
` color: /(background|color)$/i,`,
|
249
|
+
` date: /Date$/i`,
|
250
|
+
` }`,
|
251
|
+
` },`,
|
252
|
+
` options: {`,
|
253
|
+
` storySort: (a, b)=> {`,
|
254
|
+
``,
|
255
|
+
` const orderedPagesPrefix = [`,
|
256
|
+
` "Introduction",`,
|
257
|
+
` "login/login.ftl",`,
|
258
|
+
` "login/register.ftl",`,
|
259
|
+
` "login/terms.ftl",`,
|
260
|
+
` "login/error.ftl",`,
|
261
|
+
` "login/code.ftl",`,
|
262
|
+
` "login/delete-account-confirm.ftl",`,
|
263
|
+
` "login/delete-credential.ftl",`,
|
264
|
+
` "login/frontchannel-logout.ftl",`,
|
265
|
+
` "login/idp-review-user-profile.ftl",`,
|
266
|
+
` "login/info.ftl",`,
|
267
|
+
` "login/login-config-totp.ftl",`,
|
268
|
+
` "login/login-idp-link-confirm.ftl",`,
|
269
|
+
` "login/login-idp-link-email.ftl",`,
|
270
|
+
` "login/login-oauth-grant.ftl",`,
|
271
|
+
` "login/login-otp.ftl",`,
|
272
|
+
` "login/login-page-expired.ftl",`,
|
273
|
+
` "login/login-password.ftl",`,
|
274
|
+
` "login/login-reset-otp.ftl",`,
|
275
|
+
` "login/login-reset-password.ftl",`,
|
276
|
+
` "login/login-update-password.ftl",`,
|
277
|
+
` "login/login-update-profile.ftl",`,
|
278
|
+
` "login/login-username.ftl",`,
|
279
|
+
` "login/login-verify-email.ftl",`,
|
280
|
+
` "login/login-x509-info.ftl",`,
|
281
|
+
` "login/logout-confirm.ftl",`,
|
282
|
+
` "login/saml-post-form.ftl",`,
|
283
|
+
` "login/select-authenticator.ftl",`,
|
284
|
+
` "login/update-email.ftl",`,
|
285
|
+
` "login/webauthn-authenticate.ftl",`,
|
286
|
+
` "login/webauthn-error.ftl",`,
|
287
|
+
` "login/webauthn-register.ftl",`,
|
288
|
+
` "login/login-oauth2-device-verify-user-code.ftl",`,
|
289
|
+
` "login/login-recovery-authn-code-config.ftl",`,
|
290
|
+
` "login/login-recovery-authn-code-input.ftl",`,
|
291
|
+
` "account/account.ftl",`,
|
292
|
+
` "account/password.ftl",`,
|
293
|
+
` "account/federatedIdentity.ftl",`,
|
294
|
+
` "account/log.ftl",`,
|
295
|
+
` "account/sessions.ftl",`,
|
296
|
+
` "account/totp.ftl"`,
|
297
|
+
` ];`,
|
298
|
+
``,
|
299
|
+
` function getHardCodedWeight(title) {`,
|
300
|
+
` for (let i = 0; i < orderedPagesPrefix.length; i++) {`,
|
301
|
+
` if (`,
|
302
|
+
` title`,
|
303
|
+
` .toLowerCase()`,
|
304
|
+
` .startsWith(orderedPagesPrefix[i].toLowerCase())`,
|
305
|
+
` ) {`,
|
306
|
+
` return orderedPagesPrefix.length - i;`,
|
307
|
+
` }`,
|
308
|
+
` }`,
|
309
|
+
``,
|
310
|
+
` return 0;`,
|
311
|
+
` }`,
|
312
|
+
``,
|
313
|
+
` return getHardCodedWeight(b.title) - getHardCodedWeight(a.title);`,
|
314
|
+
``,
|
315
|
+
` }`,
|
316
|
+
``,
|
317
|
+
` }`,
|
318
|
+
` }`,
|
319
|
+
`};`,
|
320
|
+
``,
|
321
|
+
`export default preview;`,
|
322
|
+
``
|
323
|
+
].join("\n");
|
package/src/bin/main.ts
CHANGED
@@ -146,6 +146,20 @@ program
|
|
146
146
|
}
|
147
147
|
});
|
148
148
|
|
149
|
+
program
|
150
|
+
.command({
|
151
|
+
name: "init",
|
152
|
+
description: "(BETA) Initialize a new theme type (login/account/admin/email)"
|
153
|
+
})
|
154
|
+
.task({
|
155
|
+
skip,
|
156
|
+
handler: async ({ projectDirPath }) => {
|
157
|
+
const { command } = await import("./init");
|
158
|
+
|
159
|
+
await command({ projectDirPath: projectDirPath ?? process.cwd() });
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
149
163
|
program
|
150
164
|
.command({
|
151
165
|
name: "eject-page",
|
@@ -2,7 +2,6 @@ import { parse as urlParse } from "url";
|
|
2
2
|
import {
|
3
3
|
join as pathJoin,
|
4
4
|
sep as pathSep,
|
5
|
-
relative as pathRelative,
|
6
5
|
resolve as pathResolve,
|
7
6
|
dirname as pathDirname
|
8
7
|
} from "path";
|
@@ -13,8 +12,7 @@ import { assert, type Equals, is } from "tsafe/assert";
|
|
13
12
|
import * as child_process from "child_process";
|
14
13
|
import {
|
15
14
|
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
|
16
|
-
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
|
17
|
-
THEME_TYPES
|
15
|
+
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
|
18
16
|
} from "./constants";
|
19
17
|
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
|
20
18
|
import { exclude } from "tsafe";
|
@@ -167,40 +165,7 @@ export function getBuildContext(params: {
|
|
167
165
|
return { themeSrcDirPath };
|
168
166
|
}
|
169
167
|
|
170
|
-
{
|
171
|
-
const basenames = fs.readdirSync(srcDirPath);
|
172
|
-
|
173
|
-
for (const basename of basenames) {
|
174
|
-
const path = pathJoin(srcDirPath, basename);
|
175
|
-
|
176
|
-
if (!fs.statSync(path).isFile()) {
|
177
|
-
continue;
|
178
|
-
}
|
179
|
-
|
180
|
-
if (fs.readFileSync(path).toString("utf8").includes("./kc.gen")) {
|
181
|
-
return { themeSrcDirPath: srcDirPath };
|
182
|
-
}
|
183
|
-
}
|
184
|
-
}
|
185
|
-
|
186
|
-
for (const themeType of [...THEME_TYPES, "email"]) {
|
187
|
-
if (!fs.existsSync(pathJoin(srcDirPath, themeType))) {
|
188
|
-
continue;
|
189
|
-
}
|
190
|
-
return { themeSrcDirPath: srcDirPath };
|
191
|
-
}
|
192
|
-
|
193
|
-
console.log(
|
194
|
-
chalk.red(
|
195
|
-
[
|
196
|
-
`Can't locate your Keycloak theme source directory in .${pathSep}${pathRelative(process.cwd(), srcDirPath)}`,
|
197
|
-
`Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option`,
|
198
|
-
`If you are collocating your Keycloak theme with your app you must have a directory named '${KEYCLOAK_THEME}' or '${KEYCLOAK_THEME.replace(/-/g, "_")}' in your 'src' directory`
|
199
|
-
].join("\n")
|
200
|
-
)
|
201
|
-
);
|
202
|
-
|
203
|
-
process.exit(1);
|
168
|
+
return { themeSrcDirPath: srcDirPath };
|
204
169
|
})();
|
205
170
|
|
206
171
|
const { resolvedViteConfig } = (() => {
|
@@ -10,11 +10,13 @@ export type CommandName =
|
|
10
10
|
| "update-kc-gen"
|
11
11
|
| "eject-page"
|
12
12
|
| "add-story"
|
13
|
+
| "initialize-login-theme"
|
13
14
|
| "initialize-account-theme"
|
14
15
|
| "initialize-admin-theme"
|
15
16
|
| "initialize-admin-theme"
|
16
17
|
| "initialize-email-theme"
|
17
|
-
| "copy-keycloak-resources-to-public"
|
18
|
+
| "copy-keycloak-resources-to-public"
|
19
|
+
| "init";
|
18
20
|
|
19
21
|
export type ApiVersion = "v1";
|
20
22
|
|