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.
Files changed (39) 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 +23 -7
  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
package/bin/main.js CHANGED
@@ -194,30 +194,7 @@ function getBuildContext(params) {
194
194
  if (themeSrcDirPath !== undefined) {
195
195
  return { themeSrcDirPath };
196
196
  }
197
- {
198
- const basenames = external_fs_.readdirSync(srcDirPath);
199
- for (const basename of basenames) {
200
- const path = (0,external_path_.join)(srcDirPath, basename);
201
- if (!external_fs_.statSync(path).isFile()) {
202
- continue;
203
- }
204
- if (external_fs_.readFileSync(path).toString("utf8").includes("./kc.gen")) {
205
- return { themeSrcDirPath: srcDirPath };
206
- }
207
- }
208
- }
209
- for (const themeType of [...constants/* THEME_TYPES */.Jh, "email"]) {
210
- if (!external_fs_.existsSync((0,external_path_.join)(srcDirPath, themeType))) {
211
- continue;
212
- }
213
- return { themeSrcDirPath: srcDirPath };
214
- }
215
- console.log(source_default().red([
216
- `Can't locate your Keycloak theme source directory in .${external_path_.sep}${(0,external_path_.relative)(process.cwd(), srcDirPath)}`,
217
- `Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option`,
218
- `If you are collocating your Keycloak theme with your app you must have a directory named '${constants/* KEYCLOAK_THEME */.PC}' or '${constants/* KEYCLOAK_THEME.replace */.PC.replace(/-/g, "_")}' in your 'src' directory`
219
- ].join("\n")));
220
- process.exit(1);
197
+ return { themeSrcDirPath: srcDirPath };
221
198
  })();
222
199
  const { resolvedViteConfig } = (() => {
223
200
  if (external_fs_.readdirSync(projectDirPath)
@@ -16223,7 +16200,7 @@ program
16223
16200
  .task({
16224
16201
  skip,
16225
16202
  handler: async ({ projectDirPath }) => {
16226
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(864), __nccwpck_require__.e(712)]).then(__nccwpck_require__.bind(__nccwpck_require__, 35712));
16203
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(309), __nccwpck_require__.e(895), __nccwpck_require__.e(712)]).then(__nccwpck_require__.bind(__nccwpck_require__, 35712));
16227
16204
  await command({ buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }) });
16228
16205
  }
16229
16206
  });
@@ -16282,6 +16259,18 @@ program
16282
16259
  });
16283
16260
  }
16284
16261
  });
16262
+ program
16263
+ .command({
16264
+ name: "init",
16265
+ description: "(BETA) Initialize a new theme type (login/account/admin/email)"
16266
+ })
16267
+ .task({
16268
+ skip,
16269
+ handler: async ({ projectDirPath }) => {
16270
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(309), __nccwpck_require__.e(762)]).then(__nccwpck_require__.bind(__nccwpck_require__, 70762));
16271
+ await command({ projectDirPath: projectDirPath !== null && projectDirPath !== void 0 ? projectDirPath : process.cwd() });
16272
+ }
16273
+ });
16285
16274
  program
16286
16275
  .command({
16287
16276
  name: "eject-page",
@@ -16314,7 +16303,7 @@ program
16314
16303
  .task({
16315
16304
  skip,
16316
16305
  handler: async ({ projectDirPath }) => {
16317
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(84), __nccwpck_require__.e(618)]).then(__nccwpck_require__.bind(__nccwpck_require__, 16932));
16306
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(502), __nccwpck_require__.e(932)]).then(__nccwpck_require__.bind(__nccwpck_require__, 16932));
16318
16307
  await command({ buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }) });
16319
16308
  }
16320
16309
  });
@@ -16338,7 +16327,7 @@ program
16338
16327
  .task({
16339
16328
  skip,
16340
16329
  handler: async ({ projectDirPath }) => {
16341
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(84), __nccwpck_require__.e(313)]).then(__nccwpck_require__.bind(__nccwpck_require__, 60355));
16330
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(502), __nccwpck_require__.e(355)]).then(__nccwpck_require__.bind(__nccwpck_require__, 60355));
16342
16331
  await command({ buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }) });
16343
16332
  }
16344
16333
  });
@@ -16362,7 +16351,7 @@ program
16362
16351
  .task({
16363
16352
  skip,
16364
16353
  handler: async ({ projectDirPath }) => {
16365
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(786), __nccwpck_require__.e(433)]).then(__nccwpck_require__.bind(__nccwpck_require__, 10786));
16354
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(786), __nccwpck_require__.e(30)]).then(__nccwpck_require__.bind(__nccwpck_require__, 10786));
16366
16355
  await command({ buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }) });
16367
16356
  }
16368
16357
  });
@@ -16391,7 +16380,7 @@ program
16391
16380
  .task({
16392
16381
  skip,
16393
16382
  handler: async ({ projectDirPath }) => {
16394
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(69), __nccwpck_require__.e(84), __nccwpck_require__.e(786), __nccwpck_require__.e(97), __nccwpck_require__.e(946)]).then(__nccwpck_require__.bind(__nccwpck_require__, 74946));
16383
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(69), __nccwpck_require__.e(786), __nccwpck_require__.e(97), __nccwpck_require__.e(946)]).then(__nccwpck_require__.bind(__nccwpck_require__, 74946));
16395
16384
  await command({ buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }) });
16396
16385
  }
16397
16386
  });
@@ -16459,7 +16448,7 @@ program
16459
16448
  .task({
16460
16449
  skip,
16461
16450
  handler: async ({ projectDirPath, path, revert, public: public_params }) => {
16462
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(69), __nccwpck_require__.e(84), __nccwpck_require__.e(786), __nccwpck_require__.e(97), __nccwpck_require__.e(930)]).then(__nccwpck_require__.bind(__nccwpck_require__, 71930));
16451
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(69), __nccwpck_require__.e(786), __nccwpck_require__.e(97), __nccwpck_require__.e(930)]).then(__nccwpck_require__.bind(__nccwpck_require__, 71930));
16463
16452
  await command({
16464
16453
  buildContext: (0,buildContext/* getBuildContext */.s)({ projectDirPath }),
16465
16454
  cliCommandOptions: { path, isRevert: revert, isPublic: public_params }
@@ -1,7 +1,7 @@
1
1
  import type { BuildContext } from "./buildContext";
2
2
  export declare const BIN_NAME = "_keycloakify-custom-handler";
3
3
  export declare const NOT_IMPLEMENTED_EXIT_CODE = 78;
4
- export type CommandName = "update-kc-gen" | "eject-page" | "add-story" | "initialize-account-theme" | "initialize-admin-theme" | "initialize-admin-theme" | "initialize-email-theme" | "copy-keycloak-resources-to-public";
4
+ export type CommandName = "update-kc-gen" | "eject-page" | "add-story" | "initialize-login-theme" | "initialize-account-theme" | "initialize-admin-theme" | "initialize-admin-theme" | "initialize-email-theme" | "copy-keycloak-resources-to-public" | "init";
5
5
  export type ApiVersion = "v1";
6
6
  export declare function readParams(params: {
7
7
  apiVersion: ApiVersion;
@@ -1 +1 @@
1
- {"version":3,"file":"customHandler.js","sourceRoot":"","sources":["../../src/bin/shared/customHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,CAAC,MAAM,QAAQ,GAAG,6BAA6B,CAAC;AAEtD,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAc5C,MAAM,UAAU,UAAU,CAAC,MAAkC;IACzD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IAE9B,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAE5B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;QACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,YAAY,CAAC,CAAC;QAEpE,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QAE/B,OAAO,QAAuB,CAAC;IACnC,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE;QACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;QAErE,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QAE/B,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAiB,CAAC;IAChD,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"customHandler.js","sourceRoot":"","sources":["../../src/bin/shared/customHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,CAAC,MAAM,QAAQ,GAAG,6BAA6B,CAAC;AAEtD,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAgB5C,MAAM,UAAU,UAAU,CAAC,MAAkC;IACzD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IAE9B,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAE5B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;QACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,YAAY,CAAC,CAAC;QAEpE,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QAE/B,OAAO,QAAuB,CAAC;IACnC,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE;QACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;QAErE,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QAE/B,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAiB,CAAC;IAChD,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACzC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloakify",
3
- "version": "11.8.46",
3
+ "version": "11.8.47-rc.1",
4
4
  "description": "Framework to create custom Keycloak UIs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -655,6 +655,10 @@
655
655
  "src/bin/add-story.ts",
656
656
  "src/bin/copy-keycloak-resources-to-public.ts",
657
657
  "src/bin/eject-page.ts",
658
+ "src/bin/init/index.ts",
659
+ "src/bin/init/init.ts",
660
+ "src/bin/init/setupEslint.ts",
661
+ "src/bin/init/setupVitePluginIfNeeded.ts",
658
662
  "src/bin/initialize-account-theme/index.ts",
659
663
  "src/bin/initialize-account-theme/initialize-account-theme.ts",
660
664
  "src/bin/initialize-account-theme/multi-page-boilerplate/KcContext.ts",
@@ -664,6 +668,7 @@
664
668
  "src/bin/initialize-account-theme/updateAccountThemeImplementationInConfig.ts",
665
669
  "src/bin/initialize-admin-theme.ts",
666
670
  "src/bin/initialize-email-theme.ts",
671
+ "src/bin/initialize-login-theme.ts",
667
672
  "src/bin/keycloakify/buildJars/buildJar.ts",
668
673
  "src/bin/keycloakify/buildJars/buildJars.ts",
669
674
  "src/bin/keycloakify/buildJars/extensionVersions.ts",
@@ -1034,11 +1039,16 @@
1034
1039
  "bin/add-story.d.ts",
1035
1040
  "bin/copy-keycloak-resources-to-public.d.ts",
1036
1041
  "bin/eject-page.d.ts",
1042
+ "bin/init/index.d.ts",
1043
+ "bin/init/init.d.ts",
1044
+ "bin/init/setupEslint.d.ts",
1045
+ "bin/init/setupVitePluginIfNeeded.d.ts",
1037
1046
  "bin/initialize-account-theme/index.d.ts",
1038
1047
  "bin/initialize-account-theme/initialize-account-theme.d.ts",
1039
1048
  "bin/initialize-account-theme/updateAccountThemeImplementationInConfig.d.ts",
1040
1049
  "bin/initialize-admin-theme.d.ts",
1041
1050
  "bin/initialize-email-theme.d.ts",
1051
+ "bin/initialize-login-theme.d.ts",
1042
1052
  "bin/keycloakify/buildJars/buildJar.d.ts",
1043
1053
  "bin/keycloakify/buildJars/buildJars.d.ts",
1044
1054
  "bin/keycloakify/buildJars/extensionVersions.d.ts",
@@ -1122,27 +1132,33 @@
1122
1132
  "bin/tools/transformCodebase.d.ts",
1123
1133
  "bin/update-kc-gen.d.ts",
1124
1134
  "bin/main.js",
1135
+ "bin/254.index.js",
1125
1136
  "bin/266.index.js",
1137
+ "bin/30.index.js",
1126
1138
  "bin/304.index.js",
1127
- "bin/313.index.js",
1139
+ "bin/309.index.js",
1140
+ "bin/311.index.js",
1141
+ "bin/355.index.js",
1128
1142
  "bin/369.index.js",
1129
1143
  "bin/375.index.js",
1130
1144
  "bin/40.index.js",
1131
- "bin/433.index.js",
1132
1145
  "bin/453.index.js",
1133
- "bin/618.index.js",
1146
+ "bin/502.index.js",
1147
+ "bin/626.index.js",
1148
+ "bin/656.index.js",
1134
1149
  "bin/658.index.js",
1150
+ "bin/675.index.js",
1135
1151
  "bin/69.index.js",
1136
- "bin/698.index.js",
1137
1152
  "bin/712.index.js",
1138
1153
  "bin/720.index.js",
1154
+ "bin/762.index.js",
1139
1155
  "bin/780.index.js",
1140
1156
  "bin/786.index.js",
1141
- "bin/84.index.js",
1142
- "bin/864.index.js",
1143
1157
  "bin/877.index.js",
1158
+ "bin/895.index.js",
1144
1159
  "bin/910.index.js",
1145
1160
  "bin/930.index.js",
1161
+ "bin/932.index.js",
1146
1162
  "bin/946.index.js",
1147
1163
  "bin/949.index.js",
1148
1164
  "bin/97.index.js",
@@ -0,0 +1 @@
1
+ export * from "./init";
@@ -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
+ }