keycloakify 11.8.45 → 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.
Files changed (98) hide show
  1. package/bin/254.index.js +283 -0
  2. package/bin/30.index.js +25 -0
  3. package/bin/{864.index.js → 309.index.js} +6944 -28439
  4. package/bin/311.index.js +198 -0
  5. package/bin/{313.index.js → 355.index.js} +101 -147
  6. package/bin/{84.index.js → 502.index.js} +147 -101
  7. package/bin/626.index.js +194 -0
  8. package/bin/{698.index.js → 656.index.js} +101 -147
  9. package/bin/675.index.js +177 -0
  10. package/bin/69.index.js +1 -1
  11. package/bin/762.index.js +1475 -0
  12. package/bin/780.index.js +4 -2
  13. package/bin/786.index.js +115 -0
  14. package/bin/895.index.js +21501 -0
  15. package/bin/{618.index.js → 932.index.js} +117 -163
  16. package/bin/949.index.js +1 -1
  17. package/bin/97.index.js +537 -4
  18. package/bin/init/index.d.ts +1 -0
  19. package/bin/init/init.d.ts +3 -0
  20. package/bin/init/setupEslint.d.ts +4 -0
  21. package/bin/init/setupVitePluginIfNeeded.d.ts +4 -0
  22. package/bin/initialize-login-theme.d.ts +4 -0
  23. package/bin/main.js +19 -30
  24. package/bin/shared/customHandler.d.ts +1 -1
  25. package/bin/shared/customHandler.js.map +1 -1
  26. package/package.json +82 -66
  27. package/src/bin/init/index.ts +1 -0
  28. package/src/bin/init/init.ts +354 -0
  29. package/src/bin/init/setupEslint.ts +80 -0
  30. package/src/bin/init/setupVitePluginIfNeeded.ts +143 -0
  31. package/src/bin/initialize-account-theme/initialize-account-theme.ts +4 -0
  32. package/src/bin/initialize-login-theme.ts +323 -0
  33. package/src/bin/main.ts +14 -0
  34. package/src/bin/shared/buildContext.ts +2 -37
  35. package/src/bin/shared/customHandler.ts +3 -1
  36. package/src/bin/sync-extensions/extensionModuleMeta.ts +89 -73
  37. package/src/bin/sync-extensions/managedGitignoreFiles.ts +32 -2
  38. package/vite-plugin/index.js +1 -24
  39. package/bin/433.index.js +0 -140
  40. /package/res/public/keycloakify-dev-resources/account/{account/css → css}/account.css +0 -0
  41. /package/res/public/keycloakify-dev-resources/account/{account/img → img}/icon-sidebar-active.png +0 -0
  42. /package/res/public/keycloakify-dev-resources/account/{account/img → img}/keycloak-logo.png +0 -0
  43. /package/res/public/keycloakify-dev-resources/account/{account/img → img}/logo.png +0 -0
  44. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/img/favicon.ico +0 -0
  45. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly-additions.min.css +0 -0
  46. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly.min.css +0 -0
  47. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
  48. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
  49. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
  50. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
  51. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
  52. /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
  53. /package/res/public/keycloakify-dev-resources/login/{login/css → css}/login.css +0 -0
  54. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-error-arrow-down.png +0 -0
  55. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-error-sign.png +0 -0
  56. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-success-arrow-down.png +0 -0
  57. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-success-sign.png +0 -0
  58. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-warning-arrow-down.png +0 -0
  59. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-warning-sign.png +0 -0
  60. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-bg.png +0 -0
  61. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-logo-text.png +0 -0
  62. /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-logo.png +0 -0
  63. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/authChecker.js +0 -0
  64. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/common.js +0 -0
  65. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcMultivalued.js +0 -0
  66. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcNumberFormat.js +0 -0
  67. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcNumberUnFormat.js +0 -0
  68. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/menu-button-links.js +0 -0
  69. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/passkeysConditionalAuth.js +0 -0
  70. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/passwordVisibility.js +0 -0
  71. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/userProfile.js +0 -0
  72. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/webauthnAuthenticate.js +0 -0
  73. /package/res/public/keycloakify-dev-resources/login/{login/js → js}/webauthnRegister.js +0 -0
  74. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/img/favicon.ico +0 -0
  75. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/lib/pficon/pficon.css +0 -0
  76. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/lib/pficon/pficon.woff2 +0 -0
  77. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff +0 -0
  78. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff2 +0 -0
  79. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff +0 -0
  80. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff2 +0 -0
  81. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/patternfly.min.css +0 -0
  82. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/jquery/dist/jquery.min.js +0 -0
  83. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly-additions.min.css +0 -0
  84. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly.min.css +0 -0
  85. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf +0 -0
  86. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff +0 -0
  87. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
  88. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
  89. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
  90. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
  91. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.ttf +0 -0
  92. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.woff +0 -0
  93. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.woff2 +0 -0
  94. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
  95. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
  96. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/fontawesome-webfont.woff2 +0 -0
  97. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/img/bg-login.jpg +0 -0
  98. /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/rfc4648/lib/rfc4648.js +0 -0
@@ -0,0 +1,354 @@
1
+ import { setupVitePluginIfNeeded } from "./setupVitePluginIfNeeded";
2
+ import { setupEslint } from "./setupEslint";
3
+ import { getBuildContext } from "../shared/buildContext";
4
+ import { maybeDelegateCommandToCustomHandler } from "../shared/customHandler_delegate";
5
+ import { z } from "zod";
6
+ import { assert, type Equals, is } from "tsafe/assert";
7
+ import { id } from "tsafe/id";
8
+ import * as fs from "fs/promises";
9
+ import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
10
+ import cliSelect from "cli-select";
11
+ import { THEME_TYPES } from "../shared/constants";
12
+ import chalk from "chalk";
13
+ import { join as pathJoin, relative as pathRelative } from "path";
14
+ import { existsAsync } from "../tools/fs.existsAsync";
15
+ import { KEYCLOAK_THEME } from "../shared/constants";
16
+
17
+ export async function command(params: { projectDirPath: string }) {
18
+ const { projectDirPath } = params;
19
+
20
+ await setupVitePluginIfNeeded({ projectDirPath });
21
+
22
+ const buildContext = getBuildContext({ projectDirPath });
23
+
24
+ const { hasBeenHandled } = await maybeDelegateCommandToCustomHandler({
25
+ commandName: "init",
26
+ buildContext
27
+ });
28
+
29
+ if (hasBeenHandled) {
30
+ return;
31
+ }
32
+
33
+ await setupEslint({ projectDirPath });
34
+
35
+ let doAddRunDevScript = false;
36
+
37
+ setup_src: {
38
+ if (buildContext.bundler !== "vite") {
39
+ break setup_src;
40
+ }
41
+
42
+ const srcDirPath = pathJoin(buildContext.projectDirPath, "src");
43
+
44
+ const mainTsxFilePath = pathJoin(srcDirPath, "main.tsx");
45
+
46
+ if (!(await existsAsync(mainTsxFilePath))) {
47
+ break setup_src;
48
+ }
49
+
50
+ const isAlreadySetup = await (async () => {
51
+ if (buildContext.themeSrcDirPath !== srcDirPath) {
52
+ return true;
53
+ }
54
+
55
+ {
56
+ const basenames = await fs.readdir(srcDirPath);
57
+
58
+ for (const basename of basenames) {
59
+ const path = pathJoin(srcDirPath, basename);
60
+
61
+ if (!(await fs.stat(path)).isFile()) {
62
+ continue;
63
+ }
64
+
65
+ if ((await fs.readFile(path)).toString("utf8").includes("./kc.gen")) {
66
+ return true;
67
+ }
68
+ }
69
+ }
70
+
71
+ for (const themeType of [...THEME_TYPES, "email"]) {
72
+ if (!(await existsAsync(pathJoin(srcDirPath, themeType)))) {
73
+ continue;
74
+ }
75
+ return true;
76
+ }
77
+
78
+ return false;
79
+ })();
80
+
81
+ if (isAlreadySetup) {
82
+ break setup_src;
83
+ }
84
+
85
+ const doSetupAsStandalone = await (async () => {
86
+ const relativeProjectDirPath = pathRelative(
87
+ process.cwd(),
88
+ buildContext.projectDirPath
89
+ );
90
+
91
+ console.log(
92
+ chalk.cyan(
93
+ [
94
+ relativeProjectDirPath === ""
95
+ ? "This Vite project"
96
+ : `The Vite project at ${relativeProjectDirPath}`,
97
+ "is it dedicated *only* to building a Keycloak theme?"
98
+ ].join(" ")
99
+ )
100
+ );
101
+
102
+ const YES = "Yes — this project is only for the Keycloak theme (recommended)";
103
+ const NO =
104
+ "No — I'm building an app and a Keycloak theme in the same project (advanced)";
105
+
106
+ const { value } = await cliSelect({ values: [YES, NO] }).catch(() => {
107
+ process.exit(-1);
108
+ });
109
+
110
+ console.log(`${value}\n`);
111
+
112
+ return value === YES;
113
+ })();
114
+
115
+ let files: { relativeFilePath: string; fileContent: string }[];
116
+
117
+ if (doSetupAsStandalone) {
118
+ const viteEnvDTsFilePath = pathJoin(
119
+ buildContext.themeSrcDirPath,
120
+ "vite-env.d.ts"
121
+ );
122
+
123
+ const viteEnvDTsContent = await fs.readFile(viteEnvDTsFilePath);
124
+
125
+ await fs.rm(srcDirPath, { recursive: true });
126
+
127
+ await fs.mkdir(srcDirPath);
128
+
129
+ await fs.writeFile(viteEnvDTsFilePath, viteEnvDTsContent);
130
+
131
+ files = [
132
+ {
133
+ relativeFilePath: "main.tsx",
134
+ fileContent: [
135
+ `if (window.kcContext !== undefined) {`,
136
+ ` import("./main-kc");`,
137
+ `} else {`,
138
+ ` import("./main-kc.dev");`,
139
+ `}`
140
+ ].join("\n")
141
+ },
142
+ {
143
+ relativeFilePath: "main-kc.dev.tsx",
144
+ fileContent: `export {};\n`
145
+ },
146
+ {
147
+ relativeFilePath: "main-kc.tsx",
148
+ fileContent: [
149
+ `import { createRoot } from "react-dom/client";`,
150
+ `import { StrictMode } from "react";`,
151
+ `import { KcPage } from "./kc.gen";`,
152
+ ``,
153
+ `if (!window.kcContext) {`,
154
+ ` throw new Error("No Keycloak context");`,
155
+ `}`,
156
+ ``,
157
+ `createRoot(document.getElementById("root")!).render(`,
158
+ ` <StrictMode>`,
159
+ ` <KcPage kcContext={window.kcContext} />`,
160
+ ` </StrictMode>`,
161
+ `);`
162
+ ].join("\n")
163
+ }
164
+ ];
165
+ } else {
166
+ doAddRunDevScript = true;
167
+
168
+ await fs.copyFile(
169
+ mainTsxFilePath,
170
+ pathJoin(buildContext.themeSrcDirPath, "main-app.tsx")
171
+ );
172
+
173
+ files = [
174
+ {
175
+ relativeFilePath: "main.tsx",
176
+ fileContent: [
177
+ `if (window.kcContext !== undefined) {`,
178
+ ` import("./keycloak-theme/main");`,
179
+ `} else if (import.meta.env.VITE_KC_DEV === "true") {`,
180
+ ` import("./keycloak-theme/main.dev");`,
181
+ `} else {`,
182
+ ` import("./main-app");`,
183
+ `}`,
184
+ ``
185
+ ].join("\n")
186
+ },
187
+ {
188
+ relativeFilePath: pathJoin(KEYCLOAK_THEME, "main.dev.tsx"),
189
+ fileContent: `export {};\n`
190
+ },
191
+ {
192
+ relativeFilePath: pathJoin(KEYCLOAK_THEME, "main.tsx"),
193
+ fileContent: [
194
+ `import { createRoot } from "react-dom/client";`,
195
+ `import { StrictMode } from "react";`,
196
+ `import { KcPage } from "./kc.gen";`,
197
+ ``,
198
+ `if (!window.kcContext) {`,
199
+ ` throw new Error("No Keycloak context");`,
200
+ `}`,
201
+ ``,
202
+ `createRoot(document.getElementById("root")!).render(`,
203
+ ` <StrictMode>`,
204
+ ` <KcPage kcContext={window.kcContext} />`,
205
+ ` </StrictMode>`,
206
+ `);`,
207
+ ``
208
+ ].join("\n")
209
+ }
210
+ ];
211
+ }
212
+
213
+ for (let { relativeFilePath, fileContent } of files) {
214
+ const filePath = pathJoin(srcDirPath, relativeFilePath);
215
+
216
+ run_prettier: {
217
+ if (!(await getIsPrettierAvailable())) {
218
+ break run_prettier;
219
+ }
220
+
221
+ fileContent = await runPrettier({
222
+ filePath: filePath,
223
+ sourceCode: fileContent
224
+ });
225
+ }
226
+
227
+ await fs.writeFile(filePath, Buffer.from(fileContent, "utf8"));
228
+ }
229
+ }
230
+
231
+ add_script: {
232
+ const parsedPackageJson = await (async () => {
233
+ type ParsedPackageJson = {
234
+ scripts: Record<string, string>;
235
+ };
236
+
237
+ const zParsedPackageJson = (() => {
238
+ type TargetType = ParsedPackageJson;
239
+
240
+ const zTargetType = z.object({
241
+ scripts: z.record(z.string(), z.string())
242
+ });
243
+
244
+ assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
245
+
246
+ return id<z.ZodType<TargetType>>(zTargetType);
247
+ })();
248
+
249
+ const parsedPackageJson = JSON.parse(
250
+ (await fs.readFile(buildContext.packageJsonFilePath)).toString("utf8")
251
+ );
252
+
253
+ zParsedPackageJson.parse(parsedPackageJson);
254
+
255
+ assert(is<ParsedPackageJson>(parsedPackageJson));
256
+
257
+ return parsedPackageJson;
258
+ })();
259
+
260
+ const SCRIPT_NAME = "build-keycloak-theme";
261
+
262
+ if (SCRIPT_NAME in parsedPackageJson.scripts) {
263
+ break add_script;
264
+ }
265
+
266
+ parsedPackageJson.scripts[SCRIPT_NAME] = "npm run build && keycloakify build";
267
+ if (doAddRunDevScript) {
268
+ parsedPackageJson.scripts["dev-keycloak-theme"] =
269
+ "VITE_KC_DEV=true npm run dev";
270
+ }
271
+
272
+ let packageJson_content = JSON.stringify(parsedPackageJson, null, 2);
273
+
274
+ run_prettier: {
275
+ if (!(await getIsPrettierAvailable())) {
276
+ break run_prettier;
277
+ }
278
+
279
+ packageJson_content = await runPrettier({
280
+ filePath: buildContext.packageJsonFilePath,
281
+ sourceCode: packageJson_content
282
+ });
283
+ }
284
+
285
+ await fs.writeFile(
286
+ buildContext.packageJsonFilePath,
287
+ Buffer.from(packageJson_content, "utf8")
288
+ );
289
+ }
290
+
291
+ const themeType = await (async () => {
292
+ const values = ([...THEME_TYPES, "email"] as const).filter(themeType => {
293
+ const wrap = buildContext.implementedThemeTypes[themeType];
294
+
295
+ return !wrap.isImplemented && !wrap.isImplemented_native;
296
+ });
297
+
298
+ if (values.length === 0) {
299
+ return undefined;
300
+ }
301
+
302
+ console.log(chalk.cyan(`\nWhich theme theme type would you like to initialize?`));
303
+
304
+ const { value } = await cliSelect({
305
+ values
306
+ }).catch(() => {
307
+ process.exit(-1);
308
+ });
309
+
310
+ console.log(value);
311
+
312
+ return value;
313
+ })();
314
+
315
+ if (themeType === undefined) {
316
+ console.log(
317
+ chalk.gray("You already have implemented a theme type of every kind, exiting")
318
+ );
319
+ process.exit(0);
320
+ }
321
+
322
+ switch (themeType) {
323
+ case "account":
324
+ {
325
+ const { command } = await import("../initialize-account-theme");
326
+
327
+ await command({ buildContext });
328
+ }
329
+ return;
330
+ case "admin":
331
+ {
332
+ const { command } = await import("../initialize-admin-theme");
333
+
334
+ await command({ buildContext });
335
+ }
336
+ return;
337
+ case "email":
338
+ {
339
+ const { command } = await import("../initialize-email-theme");
340
+
341
+ await command({ buildContext });
342
+ }
343
+ return;
344
+ case "login":
345
+ {
346
+ const { command } = await import("../initialize-login-theme");
347
+
348
+ await command({ buildContext });
349
+ }
350
+ return;
351
+ }
352
+
353
+ assert<Equals<typeof themeType, never>>;
354
+ }
@@ -0,0 +1,80 @@
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
+ /** This function will just set reportUnusedDisableDirectives to off so that we don't get warning on generated files */
11
+ export async function setupEslint(params: { projectDirPath: string }) {
12
+ const { projectDirPath } = params;
13
+
14
+ const eslintConfigJsFilePath = pathJoin(projectDirPath, "eslint.config.js");
15
+
16
+ if (!(await existsAsync(eslintConfigJsFilePath))) {
17
+ return;
18
+ }
19
+
20
+ const eslintConfigJsContent = (await fs.readFile(eslintConfigJsFilePath)).toString(
21
+ "utf8"
22
+ );
23
+
24
+ if (eslintConfigJsContent.includes("reportUnusedDisableDirectives")) {
25
+ return;
26
+ }
27
+
28
+ const root = recast.parse(eslintConfigJsContent, {
29
+ parser: {
30
+ parse: (code: string) =>
31
+ babelParser.parse(code, {
32
+ sourceType: "module",
33
+ plugins: ["typescript"]
34
+ })
35
+ }
36
+ });
37
+
38
+ recast.visit(root, {
39
+ visitExportDefaultDeclaration(path) {
40
+ // @ts-expect-error
41
+ const args = path.node.declaration.arguments;
42
+
43
+ if (!Array.isArray(args)) return false;
44
+
45
+ args.push(
46
+ babelTypes.objectExpression([
47
+ babelTypes.objectProperty(
48
+ babelTypes.identifier("linterOptions"),
49
+ babelTypes.objectExpression([
50
+ babelTypes.objectProperty(
51
+ babelTypes.identifier("reportUnusedDisableDirectives"),
52
+ babelTypes.stringLiteral("off")
53
+ )
54
+ ])
55
+ )
56
+ ])
57
+ );
58
+
59
+ return false;
60
+ }
61
+ });
62
+
63
+ let eslintConfigJsContent_modified = babelGenerate(root).code;
64
+
65
+ format: {
66
+ if (!(await getIsPrettierAvailable())) {
67
+ break format;
68
+ }
69
+
70
+ eslintConfigJsContent_modified = await runPrettier({
71
+ sourceCode: eslintConfigJsContent_modified,
72
+ filePath: eslintConfigJsFilePath
73
+ });
74
+ }
75
+
76
+ await fs.writeFile(
77
+ eslintConfigJsFilePath,
78
+ Buffer.from(eslintConfigJsContent_modified, "utf8")
79
+ );
80
+ }
@@ -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
  {