keycloakify 11.6.1 → 11.7.0

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 (96) hide show
  1. package/bin/{653.index.js → 288.index.js} +221 -201
  2. package/bin/313.index.js +377 -0
  3. package/bin/{174.index.js → 33.index.js} +37 -2
  4. package/bin/{615.index.js → 355.index.js} +353 -102
  5. package/bin/363.index.js +1537 -0
  6. package/bin/453.index.js +6 -42
  7. package/bin/{503.index.js → 678.index.js} +577 -53
  8. package/bin/{921.index.js → 780.index.js} +54 -45
  9. package/bin/880.index.js +206 -21
  10. package/bin/9.index.js +850 -0
  11. package/bin/{525.index.js → 911.index.js} +1302 -2
  12. package/bin/930.index.js +164 -0
  13. package/bin/946.index.js +20 -0
  14. package/bin/{153.index.js → 947.index.js} +22 -797
  15. package/bin/main.js +61 -19
  16. package/bin/{eject-file.d.ts → own.d.ts} +2 -1
  17. package/bin/shared/{addPostinstallScriptIfNotPresent.d.ts → initializeSpa/addSyncExtensionsToPostinstallScript.d.ts} +1 -1
  18. package/bin/shared/initializeSpa/index.d.ts +1 -0
  19. package/bin/shared/initializeSpa/initializeSpa.d.ts +9 -0
  20. package/bin/{postinstall/uiModuleMeta.d.ts → sync-extensions/extensionModuleMeta.d.ts} +5 -5
  21. package/bin/sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.d.ts +12 -0
  22. package/bin/sync-extensions/index.d.ts +1 -0
  23. package/bin/{postinstall/installUiModulesPeerDependencies.d.ts → sync-extensions/installExtensionModulesPeerDependencies.d.ts} +3 -3
  24. package/bin/{postinstall → sync-extensions}/managedGitignoreFile.d.ts +4 -4
  25. package/bin/tools/getInstalledModuleDirPath.d.ts +0 -1
  26. package/bin/tools/isKnownByGit.d.ts +3 -0
  27. package/bin/tools/isRootPath.d.ts +1 -0
  28. package/bin/tools/listInstalledModules.d.ts +0 -1
  29. package/package.json +41 -63
  30. package/src/bin/eject-page.ts +8 -84
  31. package/src/bin/initialize-account-theme/initialize-account-theme.ts +15 -14
  32. package/src/bin/initialize-admin-theme.ts +17 -124
  33. package/src/bin/initialize-email-theme.ts +10 -34
  34. package/src/bin/keycloakify/generateResources/generateResources.ts +49 -21
  35. package/src/bin/main.ts +61 -16
  36. package/src/bin/own.ts +208 -0
  37. package/src/bin/shared/{addPostinstallScriptIfNotPresent.ts → initializeSpa/addSyncExtensionsToPostinstallScript.ts} +4 -4
  38. package/src/bin/shared/initializeSpa/index.ts +1 -0
  39. package/src/bin/shared/initializeSpa/initializeSpa.ts +149 -0
  40. package/src/bin/{postinstall/uiModuleMeta.ts → sync-extensions/extensionModuleMeta.ts} +48 -43
  41. package/src/bin/{postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts → sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.ts} +32 -21
  42. package/src/bin/sync-extensions/index.ts +1 -0
  43. package/src/bin/{postinstall/installUiModulesPeerDependencies.ts → sync-extensions/installExtensionModulesPeerDependencies.ts} +15 -13
  44. package/src/bin/{postinstall → sync-extensions}/managedGitignoreFile.ts +18 -18
  45. package/src/bin/{postinstall/postinstall.ts → sync-extensions/sync-extension.ts} +14 -26
  46. package/src/bin/tools/getInstalledModuleDirPath.ts +24 -22
  47. package/src/bin/tools/isKnownByGit.ts +45 -0
  48. package/src/bin/tools/isRootPath.ts +22 -0
  49. package/src/bin/tools/listInstalledModules.ts +4 -6
  50. package/src/bin/tools/npmInstall.ts +1 -1
  51. package/src/bin/tools/untrackFromGit.ts +19 -3
  52. package/src/bin/tsconfig.json +1 -1
  53. package/bin/300.index.js +0 -770
  54. package/bin/375.index.js +0 -4089
  55. package/bin/490.index.js +0 -1108
  56. package/bin/568.index.js +0 -1867
  57. package/bin/735.index.js +0 -907
  58. package/bin/743.index.js +0 -69
  59. package/bin/854.index.js +0 -68
  60. package/bin/initialize-account-theme/copyBoilerplate.d.ts +0 -4
  61. package/bin/initialize-account-theme/initializeAccountTheme_multiPage.d.ts +0 -3
  62. package/bin/initialize-account-theme/initializeAccountTheme_singlePage.d.ts +0 -11
  63. package/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.d.ts +0 -12
  64. package/bin/postinstall/index.d.ts +0 -1
  65. package/bin/shared/getLatestsSemVersionedTag.d.ts +0 -15
  66. package/bin/shared/promptKeycloakVersion.d.ts +0 -10
  67. package/bin/tools/OptionalIfCanBeUndefined.d.ts +0 -14
  68. package/bin/tools/crc32.d.ts +0 -9
  69. package/bin/tools/deflate.d.ts +0 -24
  70. package/bin/tools/isTrackedByGit.d.ts +0 -3
  71. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.d.ts +0 -15
  72. package/bin/tools/octokit-addons/listTags.d.ts +0 -13
  73. package/bin/tools/tee.d.ts +0 -3
  74. package/bin/tools/trimIndent.d.ts +0 -5
  75. package/src/bin/eject-file.ts +0 -68
  76. package/src/bin/initialize-account-theme/copyBoilerplate.ts +0 -32
  77. package/src/bin/initialize-account-theme/initializeAccountTheme_multiPage.ts +0 -21
  78. package/src/bin/initialize-account-theme/initializeAccountTheme_singlePage.ts +0 -142
  79. package/src/bin/initialize-account-theme/src/single-page/KcContext.ts +0 -7
  80. package/src/bin/initialize-account-theme/src/single-page/KcPage.tsx +0 -11
  81. package/src/bin/postinstall/index.ts +0 -1
  82. package/src/bin/shared/getLatestsSemVersionedTag.ts +0 -201
  83. package/src/bin/shared/promptKeycloakVersion.ts +0 -72
  84. package/src/bin/tools/OptionalIfCanBeUndefined.ts +0 -12
  85. package/src/bin/tools/crc32.ts +0 -73
  86. package/src/bin/tools/deflate.ts +0 -61
  87. package/src/bin/tools/isTrackedByGit.ts +0 -29
  88. package/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +0 -47
  89. package/src/bin/tools/octokit-addons/listTags.ts +0 -60
  90. package/src/bin/tools/tee.ts +0 -39
  91. package/src/bin/tools/trimIndent.ts +0 -49
  92. /package/bin/{postinstall/postinstall.d.ts → sync-extensions/sync-extension.d.ts} +0 -0
  93. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcContext.ts +0 -0
  94. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPage.tsx +0 -0
  95. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPageStory.tsx +0 -0
  96. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/i18n.ts +0 -0
package/src/bin/own.ts ADDED
@@ -0,0 +1,208 @@
1
+ import type { BuildContext } from "./shared/buildContext";
2
+ import { getExtensionModuleFileSourceCodeReadyToBeCopied } from "./sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied";
3
+ import type { ExtensionModuleMeta } from "./sync-extensions/extensionModuleMeta";
4
+ import { command as command_syncExtensions } from "./sync-extensions/sync-extension";
5
+ import {
6
+ readManagedGitignoreFile,
7
+ writeManagedGitignoreFile
8
+ } from "./sync-extensions/managedGitignoreFile";
9
+ import { getExtensionModuleMetas } from "./sync-extensions/extensionModuleMeta";
10
+ import { getAbsoluteAndInOsFormatPath } from "./tools/getAbsoluteAndInOsFormatPath";
11
+ import { relative as pathRelative, dirname as pathDirname, join as pathJoin } from "path";
12
+ import { getInstalledModuleDirPath } from "./tools/getInstalledModuleDirPath";
13
+ import * as fsPr from "fs/promises";
14
+ import { isInside } from "./tools/isInside";
15
+ import chalk from "chalk";
16
+
17
+ export async function command(params: {
18
+ buildContext: BuildContext;
19
+ cliCommandOptions: {
20
+ path: string;
21
+ isRevert: boolean;
22
+ };
23
+ }) {
24
+ const { buildContext, cliCommandOptions } = params;
25
+
26
+ const extensionModuleMetas = await getExtensionModuleMetas({ buildContext });
27
+
28
+ const { targetFileRelativePathsByExtensionModuleMeta } = await (async () => {
29
+ const fileOrDirectoryRelativePath = pathRelative(
30
+ buildContext.themeSrcDirPath,
31
+ getAbsoluteAndInOsFormatPath({
32
+ cwd: buildContext.themeSrcDirPath,
33
+ pathIsh: cliCommandOptions.path
34
+ })
35
+ );
36
+
37
+ const arr = extensionModuleMetas
38
+ .map(extensionModuleMeta => ({
39
+ extensionModuleMeta,
40
+ fileRelativePaths: extensionModuleMeta.files
41
+ .map(({ fileRelativePath }) => fileRelativePath)
42
+ .filter(
43
+ fileRelativePath =>
44
+ fileRelativePath === fileOrDirectoryRelativePath ||
45
+ isInside({
46
+ dirPath: fileOrDirectoryRelativePath,
47
+ filePath: fileRelativePath
48
+ })
49
+ )
50
+ }))
51
+ .filter(({ fileRelativePaths }) => fileRelativePaths.length !== 0);
52
+
53
+ const targetFileRelativePathsByExtensionModuleMeta = new Map<
54
+ ExtensionModuleMeta,
55
+ string[]
56
+ >();
57
+
58
+ for (const { extensionModuleMeta, fileRelativePaths } of arr) {
59
+ targetFileRelativePathsByExtensionModuleMeta.set(
60
+ extensionModuleMeta,
61
+ fileRelativePaths
62
+ );
63
+ }
64
+
65
+ return { targetFileRelativePathsByExtensionModuleMeta };
66
+ })();
67
+
68
+ if (targetFileRelativePathsByExtensionModuleMeta.size === 0) {
69
+ console.log(
70
+ chalk.yellow(
71
+ "There is no Keycloakify extension modules files matching the provided path."
72
+ )
73
+ );
74
+ process.exit(1);
75
+ }
76
+
77
+ const { ownedFilesRelativePaths: ownedFilesRelativePaths_current } =
78
+ await readManagedGitignoreFile({
79
+ buildContext
80
+ });
81
+
82
+ await (cliCommandOptions.isRevert ? command_revert : command_own)({
83
+ extensionModuleMetas,
84
+ targetFileRelativePathsByExtensionModuleMeta,
85
+ ownedFilesRelativePaths_current,
86
+ buildContext
87
+ });
88
+ }
89
+
90
+ type Params_subcommands = {
91
+ extensionModuleMetas: ExtensionModuleMeta[];
92
+ targetFileRelativePathsByExtensionModuleMeta: Map<ExtensionModuleMeta, string[]>;
93
+ ownedFilesRelativePaths_current: string[];
94
+ buildContext: BuildContext;
95
+ };
96
+
97
+ async function command_own(params: Params_subcommands) {
98
+ const {
99
+ extensionModuleMetas,
100
+ targetFileRelativePathsByExtensionModuleMeta,
101
+ ownedFilesRelativePaths_current,
102
+ buildContext
103
+ } = params;
104
+
105
+ await writeManagedGitignoreFile({
106
+ buildContext,
107
+ extensionModuleMetas,
108
+ ownedFilesRelativePaths: [
109
+ ...ownedFilesRelativePaths_current,
110
+ ...Array.from(targetFileRelativePathsByExtensionModuleMeta.values())
111
+ .flat()
112
+ .filter(
113
+ fileRelativePath =>
114
+ !ownedFilesRelativePaths_current.includes(fileRelativePath)
115
+ )
116
+ ]
117
+ });
118
+
119
+ const writeActions: (() => Promise<void>)[] = [];
120
+
121
+ for (const [
122
+ extensionModuleMeta,
123
+ fileRelativePaths
124
+ ] of targetFileRelativePathsByExtensionModuleMeta.entries()) {
125
+ const extensionModuleDirPath = await getInstalledModuleDirPath({
126
+ moduleName: extensionModuleMeta.moduleName,
127
+ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
128
+ });
129
+
130
+ for (const fileRelativePath of fileRelativePaths) {
131
+ if (ownedFilesRelativePaths_current.includes(fileRelativePath)) {
132
+ console.log(
133
+ chalk.grey(`You already have ownership over '${fileRelativePath}'.`)
134
+ );
135
+ continue;
136
+ }
137
+
138
+ writeActions.push(async () => {
139
+ const sourceCode = await getExtensionModuleFileSourceCodeReadyToBeCopied({
140
+ buildContext,
141
+ fileRelativePath,
142
+ isOwnershipAction: true,
143
+ extensionModuleName: extensionModuleMeta.moduleName,
144
+ extensionModuleDirPath,
145
+ extensionModuleVersion: extensionModuleMeta.version
146
+ });
147
+
148
+ await fsPr.writeFile(
149
+ pathJoin(buildContext.themeSrcDirPath, fileRelativePath),
150
+ sourceCode
151
+ );
152
+
153
+ console.log(chalk.green(`Ownership over '${fileRelativePath}' claimed.`));
154
+ });
155
+ }
156
+ }
157
+
158
+ if (writeActions.length === 0) {
159
+ console.log(chalk.yellow("No new file claimed."));
160
+ return;
161
+ }
162
+
163
+ await Promise.all(writeActions.map(action => action()));
164
+ }
165
+
166
+ async function command_revert(params: Params_subcommands) {
167
+ const {
168
+ extensionModuleMetas,
169
+ targetFileRelativePathsByExtensionModuleMeta,
170
+ ownedFilesRelativePaths_current,
171
+ buildContext
172
+ } = params;
173
+
174
+ const ownedFilesRelativePaths_toRemove = Array.from(
175
+ targetFileRelativePathsByExtensionModuleMeta.values()
176
+ )
177
+ .flat()
178
+ .filter(fileRelativePath => {
179
+ if (!ownedFilesRelativePaths_current.includes(fileRelativePath)) {
180
+ console.log(
181
+ chalk.grey(`Ownership over '${fileRelativePath}' wasn't claimed.`)
182
+ );
183
+ return false;
184
+ }
185
+
186
+ console.log(
187
+ chalk.green(`Ownership over '${fileRelativePath}' relinquished.`)
188
+ );
189
+
190
+ return true;
191
+ });
192
+
193
+ if (ownedFilesRelativePaths_toRemove.length === 0) {
194
+ console.log(chalk.yellow("No file relinquished."));
195
+ return;
196
+ }
197
+
198
+ await writeManagedGitignoreFile({
199
+ buildContext,
200
+ extensionModuleMetas,
201
+ ownedFilesRelativePaths: ownedFilesRelativePaths_current.filter(
202
+ fileRelativePath =>
203
+ !ownedFilesRelativePaths_toRemove.includes(fileRelativePath)
204
+ )
205
+ });
206
+
207
+ await command_syncExtensions({ buildContext });
208
+ }
@@ -1,6 +1,6 @@
1
1
  import { dirname as pathDirname, relative as pathRelative, sep as pathSep } from "path";
2
2
  import { assert } from "tsafe/assert";
3
- import type { BuildContext } from "./buildContext";
3
+ import type { BuildContext } from "../buildContext";
4
4
 
5
5
  export type BuildContextLike = {
6
6
  projectDirPath: string;
@@ -9,13 +9,13 @@ export type BuildContextLike = {
9
9
 
10
10
  assert<BuildContext extends BuildContextLike ? true : false>();
11
11
 
12
- export function addPostinstallScriptIfNotPresent(params: {
12
+ export function addSyncExtensionsToPostinstallScript(params: {
13
13
  parsedPackageJson: { scripts?: Record<string, string | undefined> };
14
14
  buildContext: BuildContextLike;
15
15
  }) {
16
16
  const { parsedPackageJson, buildContext } = params;
17
17
 
18
- const cmd_base = "keycloakify postinstall";
18
+ const cmd_base = "keycloakify sync-extensions";
19
19
 
20
20
  const projectCliOptionValue = (() => {
21
21
  const packageJsonDirPath = pathDirname(buildContext.packageJsonFilePath);
@@ -56,7 +56,7 @@ export function addPostinstallScriptIfNotPresent(params: {
56
56
  continue;
57
57
  }
58
58
 
59
- if (cmd_preexisting.includes(cmd_base)) {
59
+ if (!cmd_preexisting.includes(cmd_base)) {
60
60
  scripts[scriptName] = generateCmd({ cmd_preexisting });
61
61
  return;
62
62
  }
@@ -0,0 +1 @@
1
+ export * from "./initializeSpa";
@@ -0,0 +1,149 @@
1
+ import { dirname as pathDirname, join as pathJoin, relative as pathRelative } from "path";
2
+ import type { BuildContext } from "../buildContext";
3
+ import * as fs from "fs";
4
+ import { assert, is, type Equals } from "tsafe/assert";
5
+ import { id } from "tsafe/id";
6
+ import {
7
+ addSyncExtensionsToPostinstallScript,
8
+ type BuildContextLike as BuildContextLike_addSyncExtensionsToPostinstallScript
9
+ } from "./addSyncExtensionsToPostinstallScript";
10
+ import { getIsPrettierAvailable, runPrettier } from "../../tools/runPrettier";
11
+ import { npmInstall } from "../../tools/npmInstall";
12
+ import * as child_process from "child_process";
13
+ import { z } from "zod";
14
+ import chalk from "chalk";
15
+
16
+ export type BuildContextLike = BuildContextLike_addSyncExtensionsToPostinstallScript & {
17
+ themeSrcDirPath: string;
18
+ packageJsonFilePath: string;
19
+ };
20
+
21
+ assert<BuildContext extends BuildContextLike ? true : false>();
22
+
23
+ export async function initializeSpa(params: {
24
+ themeType: "account" | "admin";
25
+ buildContext: BuildContextLike;
26
+ }) {
27
+ const { themeType, buildContext } = params;
28
+
29
+ {
30
+ const themeTypeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, themeType);
31
+
32
+ if (
33
+ fs.existsSync(themeTypeSrcDirPath) &&
34
+ fs.readdirSync(themeTypeSrcDirPath).length > 0
35
+ ) {
36
+ console.warn(
37
+ chalk.red(
38
+ `There is already a ${pathRelative(
39
+ process.cwd(),
40
+ themeTypeSrcDirPath
41
+ )} directory in your project. Aborting.`
42
+ )
43
+ );
44
+
45
+ process.exit(-1);
46
+ }
47
+ }
48
+
49
+ const parsedPackageJson = (() => {
50
+ type ParsedPackageJson = {
51
+ scripts?: Record<string, string | undefined>;
52
+ dependencies?: Record<string, string | undefined>;
53
+ devDependencies?: Record<string, string | undefined>;
54
+ };
55
+
56
+ const zParsedPackageJson = (() => {
57
+ type TargetType = ParsedPackageJson;
58
+
59
+ const zTargetType = z.object({
60
+ scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
61
+ dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
62
+ devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
63
+ });
64
+
65
+ assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
66
+
67
+ return id<z.ZodType<TargetType>>(zTargetType);
68
+ })();
69
+ const parsedPackageJson = JSON.parse(
70
+ fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8")
71
+ );
72
+
73
+ zParsedPackageJson.parse(parsedPackageJson);
74
+
75
+ assert(is<ParsedPackageJson>(parsedPackageJson));
76
+
77
+ return parsedPackageJson;
78
+ })();
79
+
80
+ addSyncExtensionsToPostinstallScript({
81
+ parsedPackageJson,
82
+ buildContext
83
+ });
84
+
85
+ const uiSharedMajor = (() => {
86
+ const dependencies = {
87
+ ...parsedPackageJson.devDependencies,
88
+ ...parsedPackageJson.dependencies
89
+ };
90
+
91
+ const version = dependencies["@keycloakify/keycloak-ui-shared"];
92
+
93
+ if (version === undefined) {
94
+ return undefined;
95
+ }
96
+
97
+ const match = version.match(/^[^~]?(\d+)\./);
98
+
99
+ if (match === null) {
100
+ return undefined;
101
+ }
102
+
103
+ return match[1];
104
+ })();
105
+
106
+ const moduleName = `@keycloakify/keycloak-${themeType}-ui`;
107
+
108
+ const version = (
109
+ JSON.parse(
110
+ child_process
111
+ .execSync(`npm show ${moduleName} versions --json`)
112
+ .toString("utf8")
113
+ .trim()
114
+ ) as string[]
115
+ )
116
+ .reverse()
117
+ .filter(version => !version.includes("-"))
118
+ .find(version =>
119
+ uiSharedMajor === undefined ? true : version.startsWith(`${uiSharedMajor}.`)
120
+ );
121
+
122
+ assert(version !== undefined);
123
+
124
+ (parsedPackageJson.dependencies ??= {})[moduleName] = `~${version}`;
125
+
126
+ if (parsedPackageJson.devDependencies !== undefined) {
127
+ delete parsedPackageJson.devDependencies[moduleName];
128
+ }
129
+
130
+ {
131
+ let sourceCode = JSON.stringify(parsedPackageJson, undefined, 2);
132
+
133
+ if (await getIsPrettierAvailable()) {
134
+ sourceCode = await runPrettier({
135
+ sourceCode,
136
+ filePath: buildContext.packageJsonFilePath
137
+ });
138
+ }
139
+
140
+ fs.writeFileSync(
141
+ buildContext.packageJsonFilePath,
142
+ Buffer.from(sourceCode, "utf8")
143
+ );
144
+ }
145
+
146
+ await npmInstall({
147
+ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
148
+ });
149
+ }
@@ -10,15 +10,15 @@ import { crawlAsync } from "../tools/crawlAsync";
10
10
  import { getIsPrettierAvailable, getPrettier } from "../tools/runPrettier";
11
11
  import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
12
12
  import {
13
- getUiModuleFileSourceCodeReadyToBeCopied,
14
- type BuildContextLike as BuildContextLike_getUiModuleFileSourceCodeReadyToBeCopied
15
- } from "./getUiModuleFileSourceCodeReadyToBeCopied";
13
+ getExtensionModuleFileSourceCodeReadyToBeCopied,
14
+ type BuildContextLike as BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied
15
+ } from "./getExtensionModuleFileSourceCodeReadyToBeCopied";
16
16
  import * as crypto from "crypto";
17
17
  import { KEYCLOAK_THEME } from "../shared/constants";
18
18
  import { exclude } from "tsafe/exclude";
19
19
  import { isAmong } from "tsafe/isAmong";
20
20
 
21
- export type UiModuleMeta = {
21
+ export type ExtensionModuleMeta = {
22
22
  moduleName: string;
23
23
  version: string;
24
24
  files: {
@@ -29,8 +29,8 @@ export type UiModuleMeta = {
29
29
  peerDependencies: Record<string, string>;
30
30
  };
31
31
 
32
- const zUiModuleMeta = (() => {
33
- type ExpectedType = UiModuleMeta;
32
+ const zExtensionModuleMeta = (() => {
33
+ type ExpectedType = ExtensionModuleMeta;
34
34
 
35
35
  const zTargetType = z.object({
36
36
  moduleName: z.string(),
@@ -56,7 +56,7 @@ type ParsedCacheFile = {
56
56
  keycloakifyVersion: string;
57
57
  prettierConfigHash: string | null;
58
58
  thisFilePath: string;
59
- uiModuleMetas: UiModuleMeta[];
59
+ extensionModuleMetas: ExtensionModuleMeta[];
60
60
  };
61
61
 
62
62
  const zParsedCacheFile = (() => {
@@ -66,7 +66,7 @@ const zParsedCacheFile = (() => {
66
66
  keycloakifyVersion: z.string(),
67
67
  prettierConfigHash: z.union([z.string(), z.null()]),
68
68
  thisFilePath: z.string(),
69
- uiModuleMetas: z.array(zUiModuleMeta)
69
+ extensionModuleMetas: z.array(zExtensionModuleMeta)
70
70
  });
71
71
 
72
72
  type InferredType = z.infer<typeof zTargetType>;
@@ -76,10 +76,10 @@ const zParsedCacheFile = (() => {
76
76
  return id<z.ZodType<ExpectedType>>(zTargetType);
77
77
  })();
78
78
 
79
- const CACHE_FILE_RELATIVE_PATH = pathJoin("ui-modules", "cache.json");
79
+ const CACHE_FILE_RELATIVE_PATH = pathJoin("extension-modules", "cache.json");
80
80
 
81
81
  export type BuildContextLike =
82
- BuildContextLike_getUiModuleFileSourceCodeReadyToBeCopied & {
82
+ BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied & {
83
83
  cacheDirPath: string;
84
84
  packageJsonFilePath: string;
85
85
  projectDirPath: string;
@@ -87,9 +87,9 @@ export type BuildContextLike =
87
87
 
88
88
  assert<BuildContext extends BuildContextLike ? true : false>();
89
89
 
90
- export async function getUiModuleMetas(params: {
90
+ export async function getExtensionModuleMetas(params: {
91
91
  buildContext: BuildContextLike;
92
- }): Promise<UiModuleMeta[]> {
92
+ }): Promise<ExtensionModuleMeta[]> {
93
93
  const { buildContext } = params;
94
94
 
95
95
  const cacheFilePath = pathJoin(buildContext.cacheDirPath, CACHE_FILE_RELATIVE_PATH);
@@ -106,10 +106,9 @@ export async function getUiModuleMetas(params: {
106
106
  return configHash;
107
107
  })();
108
108
 
109
- const installedUiModules = await (async () => {
109
+ const installedExtensionModules = await (async () => {
110
110
  const installedModulesWithKeycloakifyInTheName = await listInstalledModules({
111
111
  packageJsonFilePath: buildContext.packageJsonFilePath,
112
- projectDirPath: buildContext.packageJsonFilePath,
113
112
  filter: ({ moduleName }) =>
114
113
  moduleName.includes("keycloakify") && moduleName !== "keycloakify"
115
114
  });
@@ -134,7 +133,7 @@ export async function getUiModuleMetas(params: {
134
133
  return await fsPr.readFile(cacheFilePath);
135
134
  })();
136
135
 
137
- const uiModuleMetas_cacheUpToDate: UiModuleMeta[] = await (async () => {
136
+ const extensionModuleMetas_cacheUpToDate: ExtensionModuleMeta[] = await (async () => {
138
137
  const parsedCacheFile: ParsedCacheFile | undefined = await (async () => {
139
138
  if (cacheContent === undefined) {
140
139
  return undefined;
@@ -177,45 +176,51 @@ export async function getUiModuleMetas(params: {
177
176
  return [];
178
177
  }
179
178
 
180
- const uiModuleMetas_cacheUpToDate = parsedCacheFile.uiModuleMetas.filter(
181
- uiModuleMeta => {
182
- const correspondingInstalledUiModule = installedUiModules.find(
183
- installedUiModule =>
184
- installedUiModule.moduleName === uiModuleMeta.moduleName
185
- );
179
+ const extensionModuleMetas_cacheUpToDate =
180
+ parsedCacheFile.extensionModuleMetas.filter(extensionModuleMeta => {
181
+ const correspondingInstalledExtensionModule =
182
+ installedExtensionModules.find(
183
+ installedExtensionModule =>
184
+ installedExtensionModule.moduleName ===
185
+ extensionModuleMeta.moduleName
186
+ );
186
187
 
187
- if (correspondingInstalledUiModule === undefined) {
188
+ if (correspondingInstalledExtensionModule === undefined) {
188
189
  return false;
189
190
  }
190
191
 
191
- return correspondingInstalledUiModule.version === uiModuleMeta.version;
192
- }
193
- );
192
+ return (
193
+ correspondingInstalledExtensionModule.version ===
194
+ extensionModuleMeta.version
195
+ );
196
+ });
194
197
 
195
- return uiModuleMetas_cacheUpToDate;
198
+ return extensionModuleMetas_cacheUpToDate;
196
199
  })();
197
200
 
198
- const uiModuleMetas = await Promise.all(
199
- installedUiModules.map(
201
+ const extensionModuleMetas = await Promise.all(
202
+ installedExtensionModules.map(
200
203
  async ({
201
204
  moduleName,
202
205
  version,
203
206
  peerDependencies,
204
207
  dirPath
205
- }): Promise<UiModuleMeta> => {
208
+ }): Promise<ExtensionModuleMeta> => {
206
209
  use_cache: {
207
- const uiModuleMeta_cache = uiModuleMetas_cacheUpToDate.find(
208
- uiModuleMeta => uiModuleMeta.moduleName === moduleName
209
- );
210
+ const extensionModuleMeta_cache =
211
+ extensionModuleMetas_cacheUpToDate.find(
212
+ extensionModuleMeta =>
213
+ extensionModuleMeta.moduleName === moduleName
214
+ );
210
215
 
211
- if (uiModuleMeta_cache === undefined) {
216
+ if (extensionModuleMeta_cache === undefined) {
212
217
  break use_cache;
213
218
  }
214
219
 
215
- return uiModuleMeta_cache;
220
+ return extensionModuleMeta_cache;
216
221
  }
217
222
 
218
- const files: UiModuleMeta["files"] = [];
223
+ const files: ExtensionModuleMeta["files"] = [];
219
224
 
220
225
  {
221
226
  const srcDirPath = pathJoin(dirPath, KEYCLOAK_THEME);
@@ -225,13 +230,13 @@ export async function getUiModuleMetas(params: {
225
230
  returnedPathsType: "relative to dirPath",
226
231
  onFileFound: async fileRelativePath => {
227
232
  const sourceCode =
228
- await getUiModuleFileSourceCodeReadyToBeCopied({
233
+ await getExtensionModuleFileSourceCodeReadyToBeCopied({
229
234
  buildContext,
230
235
  fileRelativePath,
231
- isForEjection: false,
232
- uiModuleDirPath: dirPath,
233
- uiModuleName: moduleName,
234
- uiModuleVersion: version
236
+ isOwnershipAction: false,
237
+ extensionModuleDirPath: dirPath,
238
+ extensionModuleName: moduleName,
239
+ extensionModuleVersion: version
235
240
  });
236
241
 
237
242
  const hash = computeHash(sourceCode);
@@ -261,7 +266,7 @@ export async function getUiModuleMetas(params: {
261
266
  });
262
267
  }
263
268
 
264
- return id<UiModuleMeta>({
269
+ return id<ExtensionModuleMeta>({
265
270
  moduleName,
266
271
  version,
267
272
  files,
@@ -281,7 +286,7 @@ export async function getUiModuleMetas(params: {
281
286
  keycloakifyVersion,
282
287
  prettierConfigHash,
283
288
  thisFilePath: cacheFilePath,
284
- uiModuleMetas
289
+ extensionModuleMetas
285
290
  });
286
291
 
287
292
  const cacheContent_new = Buffer.from(
@@ -306,7 +311,7 @@ export async function getUiModuleMetas(params: {
306
311
  await fsPr.writeFile(cacheFilePath, cacheContent_new);
307
312
  }
308
313
 
309
- return uiModuleMetas;
314
+ return extensionModuleMetas;
310
315
  }
311
316
 
312
317
  export function computeHash(data: Buffer) {
@@ -11,40 +11,51 @@ export type BuildContextLike = {
11
11
 
12
12
  assert<BuildContext extends BuildContextLike ? true : false>();
13
13
 
14
- export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
14
+ export async function getExtensionModuleFileSourceCodeReadyToBeCopied(params: {
15
15
  buildContext: BuildContextLike;
16
16
  fileRelativePath: string;
17
- isForEjection: boolean;
18
- uiModuleDirPath: string;
19
- uiModuleName: string;
20
- uiModuleVersion: string;
17
+ isOwnershipAction: boolean;
18
+ extensionModuleDirPath: string;
19
+ extensionModuleName: string;
20
+ extensionModuleVersion: string;
21
21
  }): Promise<Buffer> {
22
22
  const {
23
23
  buildContext,
24
- uiModuleDirPath,
24
+ extensionModuleDirPath,
25
25
  fileRelativePath,
26
- isForEjection,
27
- uiModuleName,
28
- uiModuleVersion
26
+ isOwnershipAction,
27
+ extensionModuleName,
28
+ extensionModuleVersion
29
29
  } = params;
30
30
 
31
31
  let sourceCode = (
32
- await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath))
32
+ await fsPr.readFile(
33
+ pathJoin(extensionModuleDirPath, KEYCLOAK_THEME, fileRelativePath)
34
+ )
33
35
  ).toString("utf8");
34
36
 
35
37
  sourceCode = addCommentToSourceCode({
36
38
  sourceCode,
37
39
  fileRelativePath,
38
- commentLines: isForEjection
39
- ? [`This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`]
40
- : [
41
- `WARNING: Before modifying this file run the following command:`,
42
- ``,
43
- `$ npx keycloakify eject-file --file '${fileRelativePath.split(pathSep).join("/")}'`,
44
- ``,
45
- `This file comes from ${uiModuleName} version ${uiModuleVersion}.`,
46
- `This file has been copied over to your repo by your postinstall script: \`npx keycloakify postinstall\``
47
- ]
40
+ commentLines: (() => {
41
+ const path = fileRelativePath.split(pathSep).join("/");
42
+
43
+ return isOwnershipAction
44
+ ? [
45
+ `This file has been claimed for ownership from ${extensionModuleName} version ${extensionModuleVersion}.`,
46
+ `To relinquish ownership and restore this file to its original content, run the following command:`,
47
+ ``,
48
+ `$ npx keycloakify own --path '${path}' --revert`
49
+ ]
50
+ : [
51
+ `WARNING: Before modifying this file, run the following command:`,
52
+ ``,
53
+ `$ npx keycloakify own --path '${path}'`,
54
+ ``,
55
+ `This file is provided by ${extensionModuleName} version ${extensionModuleVersion}.`,
56
+ `It was copied into your repository by the postinstall script: \`keycloakify sync-extensions\`.`
57
+ ];
58
+ })()
48
59
  });
49
60
 
50
61
  const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
@@ -93,7 +104,7 @@ function addCommentToSourceCode(params: {
93
104
  `<!--`,
94
105
  ...commentLines.map(
95
106
  line =>
96
- ` ${line.replace("--file", "-f").replace("Before modifying", "Before modifying or replacing")}`
107
+ ` ${line.replace("--path", "-p").replace("Before modifying", "Before modifying or replacing")}`
97
108
  ),
98
109
  `-->`
99
110
  ].join("\n");
@@ -0,0 +1 @@
1
+ export * from "./sync-extension";